POJ3259 Wormholes(Bellmanford判断负环)

刚刚学了Bellmanford算法,于是找了道做过的模板题来试试手。当时直接用的模板,今天靠理解手打了一遍Bellmanford,进一步加深了理解。
Bellmanford算法,简而言之就是对一张有n个点的图的所有边,进行n-1次松弛操作。然后判断,如果仍然能进行第n次松弛操作,说明图里有负环,可以沿着这个负环不停地走下去让最短路径变为无穷小。
建图用的链式前向星。
前M条权值为正的边是双向边,后W条权值为负的是单向的。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=1000;
int dis[MAXN];
int head[MAXN];
struct edge{
    int to,len,next;
}E[8000];
bool bellmanford(int n){
    for(int i=2;i<=n;i++)   dis[i]=INF;
    dis[1]=0;
    for(int i=1;i<=n-1;i++)                 //对链式前向星中共2M+W条边各执行n-1次松弛操作
        {
            for(int j=1;j<=n;j++){
                if(dis[j]==INF)     continue;
                for(int k=head[j];k!=0;k=E[k].next){                        //链式前向星编号从1开始,故以K!=0结束,若从0开始,改为k!=-1结束
                    if(E[k].len!=INF&&dis[E[k].to]>(dis[j]+E[k].len)){
                        dis[E[k].to]=dis[j]+E[k].len;
                    }
                }
            }
        }

        for(int j=1;j<=n;j++){                                            //若经过以上n-1次松弛以后仍然能松弛,说明图中存在权值为负的环,无最短路径
            for(int k=head[j];k!=0;k=E[k].next){
                if(E[k].len!=INF&&dis[E[k].to]>(dis[j]+E[k].len)){
                   return false;                                           //存在负环
                }
            }
        }
        return true;                                                    //无负环


}


int main()
{

    int F,N,M,W,i,j,k;
    scanf("%d",&F);
    while(F--)
    {   memset(head,0,sizeof(head));
        scanf("%d%d%d",&N,&M,&W);
        memset(E,0,sizeof(E));
        memset(dis,0,sizeof(dis));
        for(i=1;i<=M;i++)                                    //建立了编号从12M,共2M条边(前M条与后M条一一对应为反向边)
        {   int index;
            scanf("%d%d%d",&index,&E[i].to,&E[i].len);
            E[i].next=head[index];
            head[index]=i;
            E[i+M].to=index;
            E[i+M].len=E[i].len;
            E[i+M].next=head[E[i].to];
            head[E[i].to]=i+M;


        }

        for(i=2*M+1;i<=2*M+W;i++)                                   
        {   int index;
            scanf("%d%d%d",&index,&E[i].to,&E[i].len);    //建立了编号从2M+12M+W共W条边
            E[i].len=E[i].len*(-1);
            E[i].next=head[index];
            head[index]=i;
        }
      /* for(int j=1;j<=N;j++){                                            //测试,检查建边情况
            for(int k=head[j];k!=0;k=E[k].next){
                    cout<<j<<" "<<E[k].to<<" "<<E[k].len<<endl;                                     
                }
            }       */

        if(bellmanford(N))
        {


            printf("NO\n");
        }
        else
             printf("YES\n");



    }
    return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值