您的位置:首页 > 其它

POJ3259---Wormholes(最短路:验证存在负环)

2017-06-26 19:43 344 查看
题目来源http://poj.org/problem?id=3259

【题意】

农夫有n块地,这n块地有m条路径,具有相应的时间(走这条路),同时也有w个时间 虫洞,可以从一块地到另一块地,并且减少相应的时间,问:是否能够遇到之前的自己。。。

【思路】

m条路径是双向的,而w个虫洞是单向的。而这道题也就变成了判断是否存在负数环,因为一旦有了负数环,时间会不停地减少,肯定会遇见曾经的自己的。

验证是否存在负环的方法有两种:

1、用bellman_ford算法。经验证:所有的边重复松弛n-1次就可以得到最短路。那么如果松弛n-1次后依旧可以松弛,那么可证存在负环。(验证:bellman-ford算法的基本思想是,对图中除了源顶点s外的任意顶点u,依次构造从s到u的最短路径长度序列dist[u],dis2[u]……dis(n-1)[u],其中n是图G的顶点数,dis1[u]是从s到u的只经过1条边的最短路径长度,dis2[u]是从s到u的最多经过G中2条边的最短路径长度……当图G中没有从源可达的负权图时,从s到u的最短路径上最多有n-1条边。因此,

dist(n-1)[u]就是从s到u的最短路径长度(推荐博客:算法复习 – 图论 最短路和最小生成树))

2、用spfa算法。经验证:当一个点重复进入队列n次以上,就存在负环。

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,w,k;
struct p
{
int u,v;
int t;
}edge[5210];
int d[510];
bool bellman()
{
for(int i=2;i<=n;i++)
{
d[i]=INF;
}
d[1]=0;
for(int i=1;i<n;i++)//重复n-1次
{
bool flag=1;//是否存在负环
for(int j=0;j<k;j++)//所有的边
{
if(d[edge[j].u]>d[edge[j].v]+edge[j].t)
{
d[edge[j].u]=d[edge[j].v]+edge[j].t;
flag=0;
}

}
if(flag) return 0;//若是当前这一轮没有松弛,那么一定不存在负环。
}
for(int i=0;i<k;i++)
{
if(d[edge[i].u]>d[edge[i].v]+edge[i].t)
return 1;
}
return 0;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
k=0;
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=m;i++)//双向
{
int u,v,t;
scanf("%d%d%d",&u,&v,&t);
edge[k].u=u;
edge[k].v=v;
edge[k++].t=t;
edge[k].v=u;
edge[k].u=v;
edge[k++].t=t;
}
for(int i=1;i<=w;i++)//单向
{
int u,v,t;
scanf("%d%d%d",&u,&v,&t);
edge[k].u=u;
edge[k].v=v;
edge[k++].t=-t;//时间减少
}
if(bellman())
printf("YES\n");
else
printf("NO\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: