Wormholes
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 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
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 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.
题意:
有n个点,m条普通的双向的路,w条单向的虫洞,问是否能从某个点出发走一些路再回来时回到过去。
即判断是否有负环。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<stack> 6 #include<algorithm> 7 #include<cmath> 8 #include<vector> 9 #define N 50000//记得开大一点,做的时候开5000RE了好几遍 10 #define inf 0x3f3f3f 11 using namespace std; 12 13 struct node 14 { 15 int to,w,next; 16 } s[N]; 17 18 int n; 19 int tot; 20 int vis[N]; 21 int dis[N]; 22 int head[N]; 23 int num[N]; 24 25 void add(int u,int v,int w)//记得这个函数存的是边的信息(编号为tot的边的指向以及权值),而不是点的信息, 26 { 27 s[tot].to = v; 28 s[tot].w = w; 29 s[tot].next = head[u]; 30 head[u] = tot++;//边的个数 31 } 32 33 int spfa() 34 { 35 queue<int> q; 36 memset(num,0,sizeof(num)); 37 memset(vis,0,sizeof(vis)); 38 for(int i = 1; i <= n; i++)//这里初始化可以用memset 39 { 40 dis[i] = inf; 41 } 42 dis[1] = 0; 43 num[1] = 1; 44 vis[1] = 1; 45 q.push(1); 46 while(q.size()) 47 { 48 int u = q.front(); 49 q.pop(); 50 vis[u] = 0; 51 for(int i = head[u]; i != -1; i = s[i].next) 52 { 53 int v = s[i].to; 54 if(dis[v] > dis[u] + s[i].w) 55 { 56 dis[v] = dis[u] + s[i].w; 57 if(vis[v] == 0) 58 { 59 num[v]++; 60 if(num[v] >= n)//如果入队次数大于点的个数则存在负环 61 return 1; 62 vis[v] = 1; 63 q.push(v); 64 } 65 } 66 } 67 } 68 return 0; 69 } 70 71 int main() 72 { 73 int t,x,y; 74 int u,v,w; 75 scanf("%d",&t); 76 while(t--) 77 { 78 tot = 1;//tot为0或1没差 79 memset(head,-1,sizeof(head)); 80 scanf("%d %d %d",&n,&x,&y); 81 while(x--) 82 { 83 scanf("%d %d %d",&u,&v,&w); 84 add(u,v,w); 85 add(v,u,w); 86 } 87 while(y--) 88 { 89 scanf("%d %d %d",&u,&v,&w); 90 add(u,v,w*(-1)); 91 } 92 if(spfa()) 93 printf("YES\n"); 94 else 95 printf("NO\n"); 96 } 97 return 0; 98 }
#include<cstdio> #include<queue> using namespace std; const int N = 510; const int INF = 0x7fffffff; int g[N][N], n, d[N]; int cnt[N]; bool in_q[N]; //SPFA算法 bool SPFA(int s) { queue<int> q; //建立队列 for( int i = 1 ; i <= n ; i++ ) { cnt[i] = 0; //初始化扩展计数器 d[i] = INF; //初始化d值 in_q[i] = false; //初始化in队列标记 } q.push(s); //起点入队列 cnt[s]++; //扩展计数器自加 d[s] = 0; //到起点距离置0 in_q[s] = true; //标记in队列 while(!q.empty()) { int v = q.front(); q.pop(); //队头出队列 in_q[v] = false; //标记出队列 for( int i = 1 ; i <= n ; i++ ) { if( g[v][i] < INF && d[v]+g[v][i] < d[i] ) { d[i] = d[v]+g[v][i]; //松弛 if(!in_q[i]) //如果不在队列中 { in_q[i] = true; //入队列 if( ++cnt[i] >= n ) return true; q.push(i); } } } } return false; } int main() { int fn, m, w; scanf("%d", &fn); while(fn--) { scanf("%d%d%d", &n, &m, &w); for( int i = 1 ; i <= n ; i++ ) for( int j = i+1 ; j <= n ; j++ ) g[i][j] = g[j][i] = INF; //初始化邻接矩阵 while(m--) { int s, e, t; scanf("%d%d%d", &s, &e, &t); if( t < g[s][e] ) //处理重边 g[s][e] = g[e][s] = t; } while(w--) { int s, e, t; scanf("%d%d%d", &s, &e, &t); g[s][e] = -t; } printf("%s\n", SPFA(1)?"YES":"NO"); //只试起点1 } return 0; }