zoukankan      html  css  js  c++  java
  • 图论:最短路-Bellman-Ford

    我们之前介绍了一种,(最常用的)SPFA算法,SPFA算法是对Bellman-Ford算法的队列优化,用队列替代了Bellman-Ford中的循环检查部分

    然后这里我们介绍Bellman-Ford算法是为了介绍其对负权环的判定部分,以及这部分在SPFA的体现

    首先是建图部分,邻接链表,其实对于Bellman-Ford算法来说,边表足矣

    int g[maxn],d[maxn];
    struct Edge{int u,t,w,next;}e[maxm];
    void addedge(int x,int y,int z)
    {
        cnt++;e[cnt].u=x;e[cnt].t=y;e[cnt].w=z;
        e[cnt].next=g[x];g[x]=cnt;
    }

    原本青涩的邻接表变成了现在的样子,自从看了黄学长的代码风格,压行写可能更加舒适一些。。

    这里我们对于每一条边,记录其起始节点,和边表结构统一

    然后,是算法的核心部分:

        for(int i=1;i<=n;i++) d[i]=INF;
        d[s]=0;
        for(int k=0;k<n-1;k++)
        for(int i=1;i<=m;i++)
        {
            int x=e[i].u,y=e[i].t;
            if(d[x]<INF) d[y]=min(d[y],d[x]+e[i].w);
        }

    其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在n-1次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成

    然后是对于负权环的判断部分:

        bool flag=1;
        for(int i=1;i<=m;i++)  
        if(d[e[i].t]>d[e[i].u]+e[i].w){flag = 0;break;}  
        return flag;  

    对于每一条边进行检查,如果发现还能松弛,就存在负权环

    最后给出完整实现,请注意如果每一条边的长度过大,在INF处一定不要越界,还有无向图的二倍边一定要记住

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=10005;
     5 const int maxm=500005;
     6 const int INF=0x7fffffff; 
     7 int s,n,m,cnt;
     8 int g[maxn],d[maxn];
     9 struct Edge{int u,t,w,next;}e[maxm];
    10 void addedge(int x,int y,int z)
    11 {
    12     cnt++;e[cnt].u=x;e[cnt].t=y;e[cnt].w=z;
    13     e[cnt].next=g[x];g[x]=cnt;
    14 }
    15 bool bellman_ford(int s)
    16 {
    17     for(int i=1;i<=n;i++) d[i]=INF;
    18     d[s]=0;
    19     for(int k=0;k<n-1;k++)
    20     for(int i=1;i<=m;i++)
    21     {
    22         int x=e[i].u,y=e[i].t;
    23         if(d[x]<INF) d[y]=min(d[y],d[x]+e[i].w);
    24     }
    25     bool flag=1;
    26     for(int i=1;i<=m;i++)  
    27     if(d[e[i].t]>d[e[i].u]+e[i].w){flag = 0;break;}  
    28     return flag;  
    29 }
    30 int main()
    31 {
    32     scanf("%d%d%d",&n,&m,&s);
    33     int x,y,z;
    34     for(int i=1;i<=m;i++) {scanf("%d%d%d",&x,&y,&z);addedge(x,y,z);}
    35     bellman_ford(s);
    36     for(int i=1;i<=n;i++) {printf("%d ",d[i]);}
    37     return 0;
    38 }

    在SPFA中开一个数组记录每一个点的入队次数,如果一个点重复入队了n次,说明存在负权环

    总体来说,SPFA算法比Bellman-Ford更加优越,稠密图情况二者的效率是差不多的

    稀疏图来说,SPFA可能要快于Dijkstra并且,网格图可以把SPFA卡回原型

  • 相关阅读:
    oracle一次删除多张表
    JS学习之动态加载script和style样式
    JS动态引入js、CSS动态创建script/link/style标签
    js设置全局变量ajax中赋值
    java获取程序执行时间
    echarts学习总结(二):一个页面存在多个echarts图形,图形自适应窗口大小
    Codeforces Round #188 (Div. 1) B. Ants 暴力
    Codeforces Round #188 (Div. 2) C. Perfect Pair 数学
    Codeforces Round #188 (Div. 2) B. Strings of Power 水题
    Codeforces Round #188 (Div. 2) A. Even Odds 水题
  • 原文地址:https://www.cnblogs.com/aininot260/p/9382853.html
Copyright © 2011-2022 走看看