讨论版题面
虫洞(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;
}