POJ 3259:Wormholes

Description

John农夫拥有许多农场,John发现了许多神奇的树洞。这些树洞 都非常特殊因为进入树洞后能够把你送到一个目的地,并且到达目的地时的时间早于你进入树洞时的时间(比如你进入洞时是2000年,但是出洞时发现是1990年)。每个农场都有N(1<=N<=500)个field,记为1...N,M(1<=M<=2500)条path,W(1<=W<=200)个wormhole。
 
John是一个很喜欢穿越的人,他想从某个区域进入,并且经过一系列的路径或树洞 ,最后到达起点,并且到达起点时发现比最初在起点的时间还早。
 
为了帮助John实现这个愿望,他提供给我们他的F(1<=F<=5)个farm的地图。已知穿过每一条path的时间都小于等于10000s,穿过每个树洞所倒退的时间小于等于10000s。

Input

第一行是farm的个数。
第二行是第一个farm的field个数N,path的个数M,树洞的个数W。
第3~M+2 行是 path 的起点、终点、穿越时间(注意,这里的path都是双向边)
第M+3~M+W+2 行是树洞的起点、终点、倒退时间(单向边)
接着是第二个farm。
 

Output

对于每个farm,如果这个farm能够达成目标,则输出“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

对于 Sample Input :

farm 1 不能够达到目标。

farm 2 能够,因为 1->2->3->1,他回到1时比原来提前了1秒。

算法思想

将field作为节点,path作为正权边,wormholes作为负权边,注意:path是双向边。

第一步:添加一个虚拟源点s,并将这个虚拟源点连向所有的节点(field),因此共有N+1个节点,2*M+W+N条边。

第二步:对虚拟源点s运行Bellman-Ford算法,判断是否有源点可达负圈即可。

算法实现

  1   2 
  3 import java.util.Scanner;
  4 
  5 public class Main {
  6     int n;            // 节点个数
  7     int m;            // 边的个数
  8     int head[];        // head[i] 表示节点i指向的第一条边的索引是多少
  9     int edge[][];    // edge[i]表示第i条边 ,edge[i][1]表示这条边的起点,edge[i][2]表示这条边的终点,edge[i][3]表示这条边的权重
 10     int next[];        // next[i]表示第i条边在邻接表中的下一条边是什么
 11     int d[];        // d[i]表示第i条边的d值 
 12     
 13     int farmNumber;
 14     int N[];
 15     int M[];
 16     int W[];
 17     int current_farm = 0;
 18     
 19     public void getSingleFarm(Scanner in){
 20         int current_edge = 0;
 21         N[current_farm] = in.nextInt();
 22         M[current_farm] = in.nextInt();
 23         W[current_farm] = in.nextInt();
 24         this.n = N[current_farm]+1;
 25         this.m = 2*M[current_farm]+W[current_farm]+N[current_farm];
 26         //2*M+W+N条边
 27         head = new int[n];
 28         edge = new int[m][4];
 29         next = new int[m];
 30         d = new int[n];
 31         for(int i=0;i<n;i++){
 32             head[i] = -1;
 33         }
 34         for(int i=1;i<=N[current_farm];i++){
 35             edge[current_edge][1] = 0;
 36             edge[current_edge][2] = i;
 37             edge[current_edge][3] = 0;
 38             next[current_edge] = head[0];
 39             head[0] = current_edge;
 40             current_edge++;
 41         }
 42         for(int i=1;i<=M[current_farm];i++){
 43             int from = in.nextInt();
 44             int to = in.nextInt();
 45             int cost = in.nextInt();
 46             edge[current_edge][1] = from;
 47             edge[current_edge][2] = to;
 48             edge[current_edge][3] = cost;
 49             next[current_edge] = head[from];
 50             head[from] = current_edge;
 51             current_edge++;
 52             
 53             edge[current_edge][1] = to;
 54             edge[current_edge][2] = from;
 55             edge[current_edge][3] = cost;
 56             next[current_edge] = head[to];
 57             head[to] = current_edge;
 58             current_edge++;
 59         }
 60         for(int i=1;i<=W[current_farm];i++){
 61             int from = in.nextInt();
 62             int to = in.nextInt();
 63             int cost = in.nextInt();
 64             edge[current_edge][1] = from;
 65             edge[current_edge][2] = to;
 66             edge[current_edge][3] = -cost;
 67             next[current_edge] = head[from];
 68             head[from] = current_edge;
 69             current_edge++;
 70         }
 71         current_farm++;
 72     }
 73     public void getInput(Scanner in){
 74         
 75         farmNumber = in.nextInt();
 76         N = new int[farmNumber];
 77         M = new int[farmNumber];
 78         W = new int[farmNumber];
 79         
 80         for(int i=1;i<=farmNumber;i++){
 81             getSingleFarm(in);
 82             boolean flag = BellmanFord(0);
 83             if(flag) System.out.println("NO");
 84             else System.out.println("YES");
 85             
 86         }
 87     }
 88     
 89     public boolean BellmanFord(int s){
 90         for(int i=0;i<n;i++){
 91             d[i] = Integer.MAX_VALUE;
 92         }
 93         d[s] = 0;
 94         boolean flag = true;
 95         for(int t=1;t<=n-1;t++){
 96             if(flag){
 97                 flag = false;
 98                 for(int i=0;i<n;i++){
 99                     for(int j=head[i];j!=-1;j=next[j]){
100                         if(d[edge[j][2]]>d[i]+edge[j][3]){
101                             d[edge[j][2]] = d[i] + edge[j][3];
102                             flag = true;
103                         }
104                     }
105                 }
106             }
107         }
108         for(int i=0;i<n;i++){
109             for(int j=head[i];j!=-1;j=next[j]){
110                 if(d[edge[j][2]]>d[i]+edge[j][3]){
111                     return false;
112                 }
113             }
114         }
115         return true;
116     }
117     
118     public static void main(String[] args) {
119         Main main = new Main();
120         main.getInput(new Scanner(System.in));
121         
122     }
123 }
作者:xiazdong
出处:http://blog.xiazdong.info
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
原文地址:https://www.cnblogs.com/xiazdong/p/3057240.html