Wormholes POJ

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..NM (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, FF farm descriptions follow. 
Line 1 of each farm: Three space-separated integers respectively: NM, and W 
Lines 2.. M+1 of each farm: Three space-separated numbers ( SET) that describe, respectively: a bidirectional path between S and E that requiresT seconds to traverse. Two fields might be connected by more than one path. 
Lines M+2.. MW+1 of each farm: Three space-separated numbers ( SET) 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.
 
题意:有n个点,有m个双向边,每个点上还有虫洞,虫洞为单向,边上的行走花费的时间为正,穿越虫洞会倒退时间,问从1出发,能否走一圈,通过虫洞回到出发前。输入,第一行t表示样例数,接下来第一行为n,m,w.然后有m行,分别是两点和两点之间的时间,接下来w行,表示虫洞的两点和时间。

思路:最短路,相当于有一个图,每个点之间案由路,但有的路是负的,也就是负环,求的是从1到1花费的时间为负,算法的话就只能选择SPFA算法,其他都不能得出答案。详细步骤见代码。

代码:

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 998244353
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 
 21 //ma用来存放两个点之间的距离
 22 int ma[1010][1010];
 23 //dis用来存放到1之间的距离
 24 int  dis1[1010];
 25 //vis数组标记已经找过的最大起重
 26 bool vis[1010];
 27 
 28 //m表示有m个点
 29 bool spfa(int m)
 30 {
 31     //qu用来存放需要更新的点
 32     queue<int> qu;
 33     //初始dis为最大数
 34     for(int i=1;i<=m;i++)
 35     {
 36         dis1[i]=INF;
 37     }
 38     //初始vis为0,表示所有点都未被记录
 39     memset(vis,0,sizeof(vis));
 40     //1不需要记录
 41     vis[1]=1;
 42     //1到1的距离为0
 43     dis1[1]=0;
 44     //第一个点为1,入队
 45     qu.push(1);
 46     //当队伍为空时退出
 47     while(!qu.empty())
 48     {
 49         int k=qu.front();
 50         qu.pop();
 51         //如果第1个点为负,则表示可以回到离开1 之前的时间
 52         if(dis1[1]<0)
 53         {
 54             return true;
 55         }
 56         //k的记录被推反,重新记录
 57         vis[k]=0;
 58         //遍历1到m
 59         for(int i=1;i<=m;i++)
 60         {
 61             //如果1到k之间距离加上k到i将距离比1到i点距离小则更新dis1
 62             if((dis1[k]+ma[k][i])<dis1[i])
 63             {
 64                 //更新dis[i]
 65                 dis1[i]=dis1[k]+ma[k][i];
 66                 //如果i点已被标记则不入队
 67                 if(!vis[i])
 68                 {
 69                     //由于i点距离被更新,因此需要重新遍历与i连接的点,所以将i点入队,且标记i点
 70                     qu.push(i);
 71                     vis[i]=1;
 72                 }
 73             }
 74         }
 75     }
 76     return false;
 77 }
 78 int main()
 79 {
 80     //t表示样例数
 81     int t;
 82     scanf("%d",&t);
 83     while(t--)
 84     {
 85         //n表示点的数量,m表示有几条边,w表示有几个虫洞
 86         int n,m,w;
 87         scanf("%d %d %d",&n,&m,&w);
 88         //a,b表示两个点,c表示从a到b需要的时间
 89         int a,b,c;
 90         memset(ma,INF,sizeof(ma));
 91         for(int i=1;i<=m;i++)
 92         {
 93             scanf("%d %d %d",&a,&b,&c);
 94             //ab之间是双向路,且两点之间不止有一条路
 95             ma[a][b]=ma[b][a]=min(ma[a][b],c);
 96         }
 97         for(int i=1;i<=w;i++)
 98         {
 99             scanf("%d %d %d",&a,&b,&c);
100             //虫洞的时间是倒退的所以为负
101             ma[a][b]=min(ma[a][b],-c);
102         }
103         if(spfa(n))
104         {
105             printf("YES
");
106         }
107         else
108         {
109             printf("NO
");
110         }
111     }
112 }
原文地址:https://www.cnblogs.com/mzchuan/p/11479682.html