POJ 3259 Wormholes
Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu
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.
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.
Output
Lines 1.. F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
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.
/*/ 这题是判断是否产生了负环。 由于边权出现了负数这个题目就不能用普通的最短路来算,用到Floyd 或者SPFA算法。 由于题目意思要判断是否产生了负环,可以直接用SPFA算法来判断负环。 下面这个SPFA算法,d[n]为终点,如果起点u开始到达不了某个点,那么d等于INF 如果到达的了,且路上会经过负环,所以到达那个点的时候,最短路会等于-INF 如果到达那个点的时候,是正常到达的,没有经过负环,而且可以到达,那么就是介于两者之间的一个正常的值。 AC代码: /*/
#include"algorithm" #include"iostream" #include"cstring" #include"cstdlib" #include"cstdio" #include"string" #include"vector" #include"queue" #include"cmath" using namespace std; typedef long long LL ; #define memset(x,y) memset(x,y,sizeof(x)) #define memcpy(x,y) memcpy(x,y,sizeof(x)) #define FK(x) cout<<"["<<x<<"]\n" #define bigfor(x) for(int qq=1;qq<= T ;qq++) const int spfa_v=10005; const int spfa_edge=10005; template <class T> struct SPFA { struct Edge { int v,nxt; T w; } E[spfa_edge<<1]; int Head[spfa_v],erear; T p[spfa_v],INF; typedef pair< T , int > PII; void edge_init() { memset(Head,-1); memset(E,0); memset(dis,0); erear=0; } void edge_add(int u,int v,T w) { E[erear].v=v; E[erear].w=w; E[erear].nxt=Head[u]; Head[u]=erear++; } bool dis[spfa_edge]; bool vis[spfa_edge]; int flag[spfa_edge]; void init() { memset(vis,0); memset(p,0x3f); memset(flag,0); memset(dis,0); INF=p[0]; } void run(int u,int n) { //u为起点 init(); queue<int > Q; while(!Q.empty())Q.pop(); p[u]=0; Q.push(u); while(!Q.empty()) { int a=Q.front(); Q.pop(); vis[a]=0,dis[a]=1; for(int i=Head[a]; ~i; i=E[i].nxt) { int v=E[i].v; T w=E[i].w; int s = p[a] == -INF?-INF:w+p[a]; //如果已经是负环了,后面的也赋值-INF if(s<p[v]) { p[v]=s; if(!vis[v]) { //判断是否已经走过这条边了。 vis[v]=1; flag[v]++; if(flag[v]>n)p[v]=-INF; //如果超过n次则说明已经形成了负环,值赋为-INF Q.push(v); } } } } } }; SPFA<int > sp; int main() { int T; int n,m,k,u,v,w; while(~scanf("%d",&T)) { bigfor(T) { sp.edge_init(); int sign=0; scanf("%d%d%d",&n,&m,&k); for(int i=0; i<m; i++) { scanf("%d%d%d",&u,&v,&w); sp.edge_add(u,v,w); sp.edge_add(v,u,w); } for(int i=0; i<k; i++) { scanf("%d%d%d",&u,&v,&w); sp.edge_add(u,v,-w); } for(int i=1; i<=n; i++) { if(sp.dis[i])continue; //如果这个点已经查过那就不需要再查。 sp.run(i,n); if(sp.p[i]<0) {//产生了负环sp.p[i]的值才可能为负 而且是 -INF sign=1;break; } } printf("%s\n",sign?"YES":"NO") ; } } return 0; }