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

题目来源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");
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值