蟲洞(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 號草地。當然,從這條路線上的其他草地出發,也能達到目的。
luogu題面
題目描述
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..N, M (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.
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: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2..M+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2..M+W+1 of each farm: Three space-separated numbers (S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
輸出格式:Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).
輸入輸出樣例
說明
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.
存在負環時就是可以回到過去的情況,那麼題目就轉化成了判斷圖中是否存在負環的一個題目
這個就可以用DFS版的SPFA,但是如果用原來的鬆弛方法很慢,那麼可以加速一下,把所有的距離都設置爲0,這樣就只有有負權邊的時候纔會鬆弛下去,很大程度上加速了運行速度,當然你也可以記錄下所有負權邊的起點,逐個提取跑SPFA,不過我試驗了一下,把距離設置爲0用時和記錄所有負權邊的起點的用時都是0ms,空間上記錄所有負權邊的起點不如距離設置爲0優秀,要多佔用0.05MB
但是憑我只能想到記錄所有負權邊起點。。。
那麼下邊給出所有的距離均設置爲0的寫法
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define For(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
int read()
{
bool t=0;
int a=0;
char c;
while((c=getchar())==' '||c=='\r'||c=='\n');
if(c=='-')
{
t=1;
c=getchar();
}
while(isdigit(c))
{
a*=10;
a+=c;
a-='0';
c=getchar();
}
return a*(t?-1:1);
}
struct line{
int to,next,v;
}edge[5210];
int n,m,w,dis[501],last[501],que[201];
bool vis[501],t;
void setup()
{
t=0;
memset(last,0,sizeof last);
}
void dfs(int x)
{
if(vis[x])
{
t=1;
return;
}
vis[x]=1;
int p=last[x];
while(p&&!t)
{
if(dis[edge[p].to]>edge[p].v+dis[x])
{
dis[edge[p].to]=edge[p].v+dis[x];
dfs(edge[p].to);
}
p=edge[p].next;
}
vis[x]=0;
}
void spfa(int s)
{
memset(dis,0,sizeof dis);
dfs(s);
}
void add(int from,int to,int v,int i)
{
edge[i].to=to;
edge[i].v=v;
edge[i].next=last[from];
last[from]=i;
}
int main()
{
int f=read(),tx,ty,tz;
For(i,1,f)
{
setup();
n=read();
m=read();
w=read();
m*=2;
For(j,1,m)//這裏一開始又寫錯了,j全寫的i,還是沒吸取教訓。。
{
tx=read();
ty=read();
tz=read();
add(tx,ty,tz,j++);
add(ty,tx,tz,j);
}
For(j,1,w)
{
tx=read();
ty=read();
tz=read();
que[j]=tx;
add(tx,ty,tz*(-1),m+j);
}
For(j,1,w)
{
spfa(que[j]);
if(t)
break;
}
if(t)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}