• 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 }
  • 相关阅读:
    关于flume配置加载
    ListMultimap 容器
    HotSpotOverview.pdf
    芝麻西瓜
    念念不忘必有回响
    phpstrom代码格式化
    小总结
    Redis支持的数据类型
    如何通过phpstorm查看某一行代码的变更记录
    mysql自动添加时间
  • 原文地址:https://www.cnblogs.com/mzchuan/p/11479682.html
Copyright © 2020-2023  润新知