title

「POJ3259」Wormholes - SPFA判负环

->戳我进原题

Wormholes


Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 65211 Accepted: 24284


Description

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself 😃 .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

农夫约翰在探索他的许多农场,发现了一些惊人的虫洞。虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的 \(N(1≤N≤500)\) 个农场被编号为 \(1\)..\(N\),之间有 \(M(1≤M≤2500)\) 条路径,\(W(1≤W≤200)\) 个虫洞。作为一个狂热的时间旅行 \(FJ\) 的爱好者,他要做到以下几点:开始在一个区域,通过一些路径和虫洞旅行,他要回到最开时出发的那个区域出发前的时间。也许他就能遇到自己了:)。为了帮助 \(FJ\) 找出这是否是可以或不可以,他会为你提供 \(F\) 个农场的完整的映射到 \((1≤F≤5)\) 。所有的路径所花时间都不大于 \(10000\) 秒,所有的虫洞都不大于万秒的时间回溯。

Input

Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.

\(1\) 行:一个整数 \(F\) 表示接下来会有 \(F\) 个农场说明。
每个农场第一行:分别是三个空格隔开的整数: \(N\)\(M\)\(W\)
\(2\) 行到 \(M+1\) 行:三个空格分开的数字 \((S,E,T)\) 描述,分别为:需要 \(T\) 秒走过 \(S\)\(E\) 之间的双向路径。两个区域可能由一个以上的路径来连接。
\(M +2\)\(M+ W+1\) 行:三个空格分开的数字 \((S,E,T)\) 描述虫洞,描述单向路径, \(S\)\(E\) 且回溯 \(T\) 秒。

Output

Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).

\(F\) 行,每行代表一个农场
每个农场单独的一行, “\(YES\)”表示能满足要求,”\(NO\)”表示不能满足要求。

Sample Input

2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8

Sample Output

NO
YES

Hint

For farm 1, FJ cannot travel back in time.
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.

思路

想要回到原点,虫洞让你回到过去(饥荒玩家表示b这并不能),相当于一个负权,然后判断f是否存在负环即可。

代码

#include<cstdio>
#include<cctype>
#include<iostream>
#include<queue>
#include<cstring>
#define rg register
#define int long long
using namespace std;
inline int read(){
	rg int f = 0, x = 0;
	rg char ch = getchar();
	while(!isdigit(ch))	f |= (ch == '-'), ch = getchar();
	while( isdigit(ch))	x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
	return f? -x: x;
}
const int N = 6010;
const int inf = 0x7f7f7f7f;
int T, n, m, k, head[N], tot, dis[N], u, v, w, cnt[N];
bool vis[N];
struct edge{
	int nxt, to, w;
}e[N << 1];
inline void init(){
	for(rg int i = 1; i <= n; ++i){
		if(vis[i])	vis[i] = 0;
		if(head[i])	head[i] = 0;
		if(cnt[i])	cnt[i] = 0;
	}
	memset(e, 0, sizeof(e));
	tot = 0;
}
inline void add(rg int u, rg int v, rg int w){
	e[++tot].nxt = head[u];
	e[tot].to = v;
	e[tot].w = w;
	head[u] = tot;
}
inline bool spfa(){
	for(rg int i = 1; i <= n; ++i)	dis[i] = inf;
	queue<int > q;
	dis[1] = 0;
	vis[1] = 1;
	q.push(1);
	while(!q.empty()){
		int u = q.front();
		vis[u] = false;
		q.pop();
		for(rg int i = head[u]; i; i = e[i].nxt){
			int v = e[i].to;
			if(dis[v] > dis[u] + e[i].w){
				dis[v] = dis[u] + e[i].w;
				cnt[v] = cnt[u] + 1;
				if(cnt[v] >= n)	return true;	//注意是 >= n 
				if(!vis[v]){
					vis[v] = true;
					q.push(v);
				}
			}
		}
	}
	return false;
}
signed main(){
	T = read();
	for(rg int o = 1; o <= T; ++o){
		n = read(), m = read(), k = read();
		if(o > 1)	init();
		for(rg int i = 1; i <= m; ++i){
			u = read(), v = read(), w = read();
			add(u, v, w);
			add(v, u, w);
		}
		for(rg int i = 1; i <= k; ++i){
			u = read(), v = read(), w = read();
			add(u, v, -w);
		}
		if(spfa())	puts("YES");
		else	puts("NO");
	}
	return 0;
}
posted @ 2018-09-26 20:21  Horrigue_JyowYang  阅读(113)  评论(0编辑  收藏  举报