洛谷 P2850 [USACO06DEC]蟲洞Wormholes 判負環
蟲洞(wormhole)
FJ 在農場上閑逛時,發現他的農場裏有很多蟲洞。蟲洞是一條特殊的有向路徑,當
FJ 從它的一頭走到另一頭後,他將被傳送到過去的某個時刻。FJ 的每個農場包括
N(1<=N<=500)塊按1..N 編號的草地、M(1<=M<=2500)條草地間的道路以及W(1<=W<=200)
個蟲洞。
FJ 一直以來就渴望進行時間旅行,於是他開始做如下的打算:從某塊草地出發,穿
過一些道路以及一些蟲洞,最終回到他出發的草地。這樣,他說不定能碰見過去的自
己:) 。
請你幫FJ 算一下,他是否可能找到這樣的一條路。當然,FJ 會給你他的所有
F(1<=F<=5)個農場的完整的地圖。沒有哪條道路上需要花的時間超過10,000 秒,同時,
也沒有哪個蟲洞能把FJ 帶回10,000 秒以前。
程序名: wormhole
輸入格式:
-
第1 行: 一個正整數F,即農場總數。以下依次描述各個農場的地圖
-
每個農場描述的第1 行:三個用空格隔開的整數,N、M 和W
- 每個農場描述的第2..M+1 行:每行包含三個用空格隔開的整數S、E、T,表示
編號為S 的草地和編號為E 的草地邊有一條雙向道路,通過它所花費的時間為T 秒。兩
塊草地間可能有多條道路
- 每個農場描述的第M+2..M+W+1 行:每行包含三個用空格隔開的整數S、E、T,
描述了一個起點編號為S、終點編號為E 的蟲洞。穿過這個蟲洞後,FJ 可以回到T 秒之
前 輸入樣例(wormhole.in):
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
輸入說明:
FJ 交給你兩個農場的地圖。第一個農場裏有三條道路以及一個蟲洞,第二個農場裏
有兩條道路和一個蟲洞。
輸出格式:
- 第1..F 行: 對於每個農場,如果FJ 可以實現他回到過去的願望,輸出"YES",
否則輸出"NO"(不含引號)。
輸出樣例(wormhole.out):
NO
YES
輸出說明:
在農場1 中,FJ 無法完成他期望的時間旅行。
在農場2 中,FJ 可以沿路線1->2->3->1 旅行,這樣他能在離開1 號草地前一秒回
到1 號草地。當然,從這條路線上的其他草地出發,也能達到目的。
這道題簡單來說就是判斷圖內是否存在負環;
判斷負環方法:拓撲排序或spfa
spfa判斷負環:如果任意一條邊被修改大於n次,就代表這個圖內一定存在至少一個負環。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define man 1000010 4 #define ll int 5 struct edge 6 { 7 int next,dis,to; 8 }e[man<<2]; 9 ll head[man<<2],num=0,cnt[man<<1]; 10 bool vis[man]; 11 ll dis[man<<1],t,n,m,w; 12 inline void add(ll from,ll to,ll dis) 13 { 14 e[++num].next=head[from]; 15 e[num].to=to; 16 e[num].dis=dis; 17 head[from]=num; 18 } 19 inline void clear() 20 { 21 memset(head,0,sizeof(head)); 22 memset(e,0,sizeof(e)); 23 memset(cnt,0,sizeof(cnt)); 24 num=0; 25 } 26 inline bool spfa(ll s) 27 { 28 memset(vis,0,sizeof(vis)); 29 memset(dis,0x7f,sizeof(dis)); 30 queue<int >q; 31 q.push(s);dis[s]=0;vis[s]=1; 32 do 33 { 34 int u=q.front();q.pop(); 35 vis[u]=0; 36 for(int i=head[u];i;i=e[i].next) 37 { 38 ll to=e[i].to; 39 if(dis[to]>dis[u]+e[i].dis) 40 { dis[to]=dis[u]+e[i].dis; 41 if(!vis[to]) 42 { 43 q.push(to); 44 vis[to]=1; 45 cnt[to]++; 46 } 47 if(cnt[to]>n) return 1; 48 } 49 } 50 }while(q.size()); 51 return 0; 52 } 53 int main() 54 { 55 ios::sync_with_stdio(false); 56 cin>>t; 57 while(t--) 58 { 59 clear(); 60 cin>>n>>m>>w; 61 for(int i=1,x,y,z;i<=m;i++) 62 { cin>>x>>y>>z; 63 add(x,y,z);add(y,x,z); 64 } 65 for(int i=1,x,y,z;i<=w;i++) 66 { cin>>x>>y>>z; 67 add(x,y,-z); 68 } 69 if(spfa(1)==1) cout<<"YES"<<endl; 70 else cout<<"NO"<<endl; 71 } 72 return 0; 73 }
拓撲排序:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int t,n,m,w,x,y,z,num=0,dis[10010]; 7 bool flag; 8 struct star{ 9 int from,to,dis; 10 }e[10010]; 11 void add(int from, int to, int dis){ 12 e[++num].from=from; 13 e[num].to=to; 14 e[num].dis=dis; 15 } 16 bool topsort(){ 17 memset(dis,0x7f,sizeof(dis)); 18 dis[1]=0; 19 for(int i=1;i<=n;i++){ 20 flag=0; 21 for(int j=1;j<=num;j++) 22 if(dis[e[j].to]>dis[e[j].from]+e[j].dis){ 23 flag=1; 24 dis[e[j].to]=dis[e[j].from]+e[j].dis; 25 } 26 if(!flag)return 0; 27 } 28 return 1; 29 } 30 int main(){ 31 scanf("%d",&t); 32 for(int i=1;i<=t;i++){ 33 num=0; 34 scanf("%d%d%d",&n,&m,&w); 35 for(int j=1;j<=m;j++){ 36 scanf("%d%d%d",&x,&y,&z); 37 add(x,y,z);add(y,x,z); 38 } 39 for(int j=1;j<=w;j++){ 40 scanf("%d%d%d",&x,&y,&z); 41 add(x,y,-z); 42 } 43 if(topsort())printf("YES\n"); 44 else printf("NO\n"); 45 } 46 return 0; 47 }
洛谷 P2850 [USACO06DEC]蟲洞Wormholes 判負環