1715: [Usaco2006 Dec]Wormholes 虫洞
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 910 Solved: 479
[ Submit][ Status][ Discuss]
Description
John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1..N标号)块地,并有W个虫洞。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。
Input
* 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秒前的虫洞。
Output
* Lines 1..F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"。
Sample Input
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
YES
HINT
Source
在机房激起了一波讨论后
又自己看了很多帖子、博客
一种方法是跑spfa
判某个点入队大于n次
为什么是入队大于n次而不是松弛大于n次呢
我们先举个反例
可以假设一个有两个节点的图
从1-2有10条重边
边权分别从10到1
然后完全有可能遍历的时候从边权为10的边开始更新10次
但是可以不存在负权回路
而如果真的有负环的话,它是会无限更新的
所以这样可以避免误判,并且一定找得到负环
但是spfa的复杂度是O(kE)的(k是平均每个点入队的次数)(据说一般k==2)
所以如果入队n次
可以想象这是有多慢的
所以有时可以直接判入队次数大于某个特定的数
比如一两百
听说一般不会错
但我不敢用QAQ
还有一种方法就是dfs了
如果从一个点开始dfs出去的点能回来
即路径中多次出现某个点
那么就是负环了
我们将dis初始化为inf
然后枚举每个点
将它的dis设为0
然后去dfs
然而我们会发现
我们并不需要去求最短路
我们只需要求出负环
而照上面那样做
也不是求最短路
最后每个点的dis都会变为0
所以我们直接把dis初始化为0
这样只有出现负权边,才会去走
就避免了求最短路的时间
实测快了20倍左右
刚开始邻接表开的刚刚好RE了
乱开了一波10w才AQAQ
#include<cstdio>
#include<cstring>
const int N=505,M=2507;
struct node
{
int to,next,c;
}e[100000];
int cnt;
int first[N];
void insert(int u,int v,int c)
{
e[++cnt]=(node){v,first[u],c};first[u]=cnt;
e[++cnt]=(node){u,first[v],c};first[v]=cnt;
}
int dis[N],visit[N];
bool flag;
void dfs(int x)
{
visit[x]=1;
for(int k=first[x];k;k=e[k].next)
{
if(dis[e[k].to]>dis[x]+e[k].c)
{
if(visit[e[k].to])
{
flag=1;return;
}
dis[e[k].to]=dis[x]+e[k].c;
dfs(e[k].to);
}
}
visit[x]=0;
}
int main()
{
int tt;
scanf("%d",&tt);
while(tt--)
{
int n,m,w;
scanf("%d %d %d",&n,&m,&w);
memset(dis,0,sizeof(dis));
memset(first,0,sizeof(first));
int u,v,c;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&u,&v,&c);
insert(u,v,c);
}
for(int i=1;i<=w;i++)
{
scanf("%d %d %d",&u,&v,&c);
e[++cnt]=(node){v,first[u],-c};first[u]=cnt;
}
flag=0;
memset(visit,0,sizeof(visit));
for(int i=1;i<=n&&!flag;i++) dfs(i);
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}