首页 > 代码库 > 洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解

洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=2850

【题目描述】

John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路无向边连接着N (从1..N标号)块地,并有W个虫洞(有向边)。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。

【输入格式】

* Line 1: 一个整数 F, 表示农场个数。

* Line 1 of each farm: 三个整数 N, M, W。

* Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。

* Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。

【输出格式】

* Lines 1..F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。

【样例输入】

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

【样例输出】

NO

YES

 

分析:

SPFA判断负环的方法:从任意一个点开始计算最短路,判断一个点是不是入队≥n次。如果是,则说明图中有负环。

但是这题的数据很水,所以如果按照“松弛n次”来算似乎也可以AC。

 

AC代码:

  1 #include<iostream>  2 #include<cstdio>  3 #include<cmath>  4 #include<algorithm>  5 #include<cstring>  6 #include<queue>  7   8 using namespace std;  9 const int MAXN = 2800 << 1; 10 int first[MAXN],nxt[MAXN],dis[MAXN],note[MAXN],tot; 11 int f,t,v,s,m,n,w; 12 bool use[MAXN]; 13 bool jud = false; 14  15 struct edge 16 { 17     int f,t,v; 18 }l[MAXN];//存储边  19  20 void init()//初始化  21 { 22     jud = false; 23     f = 0,t = 0,v = 0,s = 0,m = 0,n = 0; 24     tot = 0; 25     memset(first,-1,sizeof(first)); 26     memset(nxt,0,sizeof(nxt)); 27     memset(dis,0x3f,sizeof(dis)); 28     memset(note,0,sizeof(note)); 29     memset(use,0,sizeof(use)); 30 } 31  32 void build(int f,int t,int v) 33 { 34     l[++ tot] = (edge){f,t,v}; 35     nxt[tot] = first[f]; 36     first[f] = tot; 37 } 38  39 queue <int> q; 40  41 void spfa(int s) 42 { 43     while(!q.empty()) 44         q.pop(); 45          46     q.push(s); 47     use[s] = 1; 48     dis[s] = 0; 49     note[s] ++; 50      51     while(!q.empty()) 52     { 53         int u = q.front(); 54         q.pop(); 55         use[u] = 0; 56         for(int i = first[u];i != -1;i = nxt[i]) 57         { 58             int v = l[i].t;  59             if(dis[v] > dis[u] + l[i].v) 60             { 61                 dis[v] = dis[u] + l[i].v; 62                 if(!use[v]) 63                 { 64                     use[v] = 1; 65                     note[v] ++; 66                     q.push(v); 67                 } 68                 if(note[v] >= n) 69                 { 70                     jud = true; 71                     return;//入队超过n-1次,标记并退出  72                 } 73             } 74         } 75     } 76 } 77  78 int main() 79 { 80     int F; 81     scanf("%d",&F); 82     for(int x = 0;x < F;x ++) 83     { 84         init(); 85         scanf("%d%d%d",&n,&m,&w); 86         for(int i = 0;i < m;i ++) 87         { 88             scanf("%d%d%d",&f,&t,&v); 89             build(f,t,v); 90             build(t,f,v); 91             if(!s)    s = f;//任选一个点s作为起点  92         } 93         for(int i = 0;i < w;i ++) 94         { 95             scanf("%d%d%d",&f,&t,&v); 96             v *= -1;//由于虫洞能回退时间,边权是负值  97             build(f,t,v); 98         } 99         spfa(s);100         if(jud)    printf("YES\n");101         else printf("NO\n");102     }103     return 0;104 }

 

洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解