Invade the Mars

题目

网上大把

分析

显然不能简单直接最短路
城市被攻占的特点是:保护的城市都被攻占了
那么这个城市被攻占的最早时间必然是所有保护他的城市中最大的被攻占时间
于是我们可以
(dis) 表示军队走到城市 (i) 驻扎于城外的最短时间
(f) 表示所有保护他的城市中最大的被攻占时间
最短路中,对于当前点 (u)
先让他保护的点 (v) 度数--,并取 (f_v = max{dis_u})
若度数降至 (0),可松弛并将其入队
然后再考虑有向边的松弛
具体可见代码

(Code)

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

const int N = 3005 , M = 70005 , INF = 2e9;
int T , n , m , tot , h[N] , dis[N] , vis[N] , deg[N] , f[N];
vector<int> pt[N];

struct edge{int nxt , to , w;}e[2 * M];
struct node{
	int id , d;
	bool operator < (node c) const {return d > c.d;}
};
priority_queue<node> Q;

inline void add(int x , int y , int z)
{
	e[++tot] = edge{h[x] , y , z} , h[x] = tot;
}

void dijkstra()
{
	memset(vis , 0 , sizeof vis);
	while (!Q.empty()) Q.pop();
	for(register int i = 1; i <= n; i++) dis[i] = INF , f[i] = 0;
	Q.push(node{1 , dis[1] = 0});
	node now;
	while (!Q.empty())
	{
		now = Q.top() , Q.pop();
		int id = now.id , v;
		if (vis[id]) continue;
		vis[id] = 1;
		for(register int i = 0; i < pt[id].size(); i++)
		{
			v = pt[id][i];
			f[v] = max(f[v] , dis[id]);
			--deg[v];
			if (deg[v] == 0 && dis[v] != INF)
				dis[v] = max(dis[v] , f[v]) , Q.push(node{v , dis[v]});
		}
		for(register int i = h[id]; i; i = e[i].nxt)
		{
			v = e[i].to;
			if (dis[id] + e[i].w < dis[v])
			{
				dis[v] = max(dis[id] + e[i].w , f[v]);
				if (deg[v] == 0) Q.push(node{v , dis[v]});
			}
		}
	}
	printf("%d
" , dis[n]);
}

int main()
{
	scanf("%d" , &T);
	while (T--)
	{
		scanf("%d%d" , &n , &m);
		for(register int i = 1; i <= n; i++) pt[i].clear() , deg[i] = 0;
		tot = 0;
		memset(h , 0 , sizeof h);
		int x , y , z;
		for(register int i = 1; i <= m; i++)
			scanf("%d%d%d" , &x , &y , &z) , add(x , y , z);
		for(register int i = 1; i <= n; i++)
		{
			scanf("%d" , &x) , deg[i] = x;
			for(register int j = 1; j <= x; j++)
				scanf("%d" , &y) , pt[y].push_back(i);
		}
		dijkstra();
	}
}
原文地址:https://www.cnblogs.com/leiyuanze/p/13819372.html