• Bellman-Ford算法


      1 #include<stdio.h>
      2 #define max 0xffffff
      3 int g[20001][20001];    //图的邻接矩阵
      4 int dist[20001];
      5 int n;//顶点个数
      6 int m;//边个数
      7 struct Edge
      8 {
      9     int u, v, w;    //边:起点、终点、权值
     10 };
     11 Edge e[200001];
     12 bool bellman_ford(int n)//bellman-ford算法
     13 {
     14     int i, k, t,j;
     15     for(i=0;i<n;i++)
     16         dist[i]=g[0][i];//初始化
     17     for(i=1;i<=n-1;i++)
     18     {
     19 
     20     /*假设第k条边的起点是u,终点是v,以下循环考虑第k条边是否会使得源点v0到v的
     21         最短距离缩短,即判断dist[edges[k].u] + edges[k].w < dist[edges[k].v] 是否成立*/
     22         for(j=0;j<n;j++)
     23         {
     24             printf("%d ",dist[j]);
     25         }
     26        printf("
    ");
     27         for(k=1;k<=m;k++)
     28         {
     29             t=dist[e[k].u]+e[k].w;
     30             if(dist[e[k].u]<max&&t<dist[e[k].v])
     31             {
     32                 dist[e[k].v] = t;
     33             }
     34         }
     35     }
     36     /*以下是检查,若还有更新则说明存在无限循环的负值回路*/
     37     for(k = 0; k < m; k ++)
     38     {
     39         if(dist[e[k].u] != max &&dist[e[k].u] + e[k].w < dist[e[k].v])
     40         {
     41             return false;
     42         }
     43     }
     44     return true;
     45 }
     46 
     47 int main()
     48 {
     49     scanf("%d %d",&n,&m);
     50     int i,j;
     51     for(i=0;i<n;i++)
     52     {
     53         for(j=0;j<n;j++)
     54             g[i][j]=max;
     55         g[i][i]=0;
     56     }
     57     for(i=1;i<=m;i++)
     58     {
     59         int a,b,c;
     60         scanf("%d %d %d",&a,&b,&c);
     61         e[i].u=a;
     62         e[i].v=b;
     63         e[i].w=c;
     64         g[a][b]=c;
     65     }
     66     for(i=0;i<n;i++)
     67     {
     68         for(j=0;j<n;j++)
     69             printf("%d ",g[i][j]);
     70         printf("
    ");
     71     }
     72     bellman_ford(n);
     73     for(i=0;i<n;i++)
     74     {
     75         printf("%d
    ",dist[i]);
     76     }
     77 
     78     return 0;
     79 }
     80 
     81 
     82 
     83 /*
     84 
     85   7 10
     86   0 1 6
     87   0 2 5
     88   0 3 5
     89   1 4 -1
     90   2 1 -2
     91   2 4 1
     92   3 2 -2
     93   3 5 -1
     94   4 6 3
     95   5 6 3
     96   
     97 Press any key to continue
     98 
     99 
    100 */
    View Code
    Bellman-Ford算法:
    为了能够求解边上带有负值的单源最短路径问题,Bellman(贝尔曼)和Ford(福特)提出了从源点逐次绕过其他顶点,以缩短到达终点的最短路径长度的方法。
     
     
    Bellman-Ford算法思想
     
    Bellman-Ford算法构造一个最短路径长度数组序列dist 1 [u], dist 2 [u], …, dist n-1 [u]。其中:
    vdist 1 [u]为从源点v到终点u的只经过一条边的最短路径长度,并有dist 1 [u] =Edge[v][u];
    vdist 2 [u]为从源点v最多经过两条边到达终点u的最短路径长度;
    vdist 3 [u]为从源点v出发最多经过不构成负权值回路的三条边到达终点u的最短路径长度;

    ……

    vdist n-1 [u]为从源点v出发最多经过不构成负权值回路的n-1条边到达终点u的最短路径长度;
    算法的最终目的是计算出dist n-1 [u],为源点v到顶点u的最短路径长度。
     
     
    ü采用递推方式计算 dist k [u]。
    v设已经求出 dist k-1 [u] , u = 0, 1, …, n-1,此即从源点v最多经过不构成负权值回路的k-1条边到达终点u的最短路径的长度。
    v从图的邻接矩阵可以找到各个顶点j到达顶点u的距离Edge[j][u],计算min{ dist k-1 [j] + Edge[j][u] } ,可得从源点v绕过各个顶点,最多经过不构成负权值回路的k条边到达终点u的最短路径的长度。
    v比较dist k-1 [u]和min{ dist k-1 [j] + Edge[j][u] } ,取较小者作为dist k [u]的值。
     

    递推公式(求顶点u到源点v的最短路径):

    dist 1 [u] = Edge[v][u]

    dist k [u] = min{ dist k-1 [u], min{ dist k-1 [j] + Edge[j][u] } }, j=0,1,…,n-1,j≠u

    struct Edge
    {
        int u, v, w;    //边:起点、终点、权值
    };
    Edge e[10001];
    void bellman_ford(int n)//bellman-ford算法
    {
        int i, k, t;
        for(i=1;i<=n;i++)
            dist[i]=g[1][i];//初始化
        for(i=2;i<=n;i++)
        {
            for(k=1;k<=m;k++)
            {
                t=dist[e[k].u]+e[k].w;
                if(dist[e[k].u]<max&&t<dist[e[k].v])
                {
                    dist[e[k].v] = t;
                }
            }
        }
    }

    代码实现:0(v*e)
      1 #include<stdio.h>
      2 #define max 0xffffff
      3 int g[20001][20001];    //图的邻接矩阵
      4 int dist[20001];
      5 int n;//顶点个数
      6 int m;//边个数
      7 struct Edge
      8 {
      9     int u, v, w;    //边:起点、终点、权值
     10 };
     11 Edge e[200001];
     12 bool bellman_ford(int n)//bellman-ford算法
     13 {
     14     int i, k, t,j;
     15     for(i=0;i<n;i++)
     16         dist[i]=g[0][i];//初始化
     17     for(i=1;i<=n-1;i++)
     18     {
     19 
     20     /*假设第k条边的起点是u,终点是v,以下循环考虑第k条边是否会使得源点v0到v的
     21         最短距离缩短,即判断dist[edges[k].u] + edges[k].w < dist[edges[k].v] 是否成立*/
     22         for(j=0;j<n;j++)
     23         {
     24             printf("%d ",dist[j]);
     25         }
     26        printf("
    ");
     27         for(k=1;k<=m;k++)
     28         {
     29             t=dist[e[k].u]+e[k].w;
     30             if(dist[e[k].u]<max&&t<dist[e[k].v])
     31             {
     32                 dist[e[k].v] = t;
     33             }
     34         }
     35     }
     36     /*以下是检查,若还有更新则说明存在无限循环的负值回路*/
     37     for(k = 0; k < m; k ++)
     38     {
     39         if(dist[e[k].u] != max &&dist[e[k].u] + e[k].w < dist[e[k].v])
     40         {
     41             return false;
     42         }
     43     }
     44     return true;
     45 }
     46 
     47 int main()
     48 {
     49     scanf("%d %d",&n,&m);
     50     int i,j;
     51     for(i=0;i<n;i++)
     52     {
     53         for(j=0;j<n;j++)
     54             g[i][j]=max;
     55         g[i][i]=0;
     56     }
     57     for(i=1;i<=m;i++)
     58     {
     59         int a,b,c;
     60         scanf("%d %d %d",&a,&b,&c);
     61         e[i].u=a;
     62         e[i].v=b;
     63         e[i].w=c;
     64         g[a][b]=c;
     65     }
     66     for(i=0;i<n;i++)
     67     {
     68         for(j=0;j<n;j++)
     69             printf("%d ",g[i][j]);
     70         printf("
    ");
     71     }
     72     bellman_ford(n);
     73     for(i=0;i<n;i++)
     74     {
     75         printf("%d
    ",dist[i]);
     76     }
     77 
     78     return 0;
     79 }
     80 
     81 
     82 
     83 /*
     84 
     85   7 10
     86   0 1 6
     87   0 2 5
     88   0 3 5
     89   1 4 -1
     90   2 1 -2
     91   2 4 1
     92   3 2 -2
     93   3 5 -1
     94   4 6 3
     95   5 6 3
     96   
     97 Press any key to continue
     98 
     99 
    100 */
    View Code
     
     0(n*n*n)
     1 void bellman_ford(int n)//bellman-ford算法
     2 {
     3     int i, k, t,j;
     4     for(i=1;i<=n;i++)
     5         dist[i]=g[1][i];//初始化
     6     for(k=1;k<=n;k++)
     7     {
     8         for(j=1;j<=n;j++)
     9         {
    10             for(i=2;i<=n;i++)
    11             {
    12                 if(g[i][j]<max&&dist[i]+g[i][j]<dist[j])
    13                     dist[j]=dist[i]+g[i][j];
    14             }
    15         }
    16     }
    17 }
    View Code
  • 相关阅读:
    BZOJ.3884.上帝与集合的正确用法(扩展欧拉定理)
    HDU.5608.function(杜教筛)
    HDU.5628.Clarke and math(狄利克雷卷积 快速幂)
    51Nod.1244.莫比乌斯函数之和(杜教筛)
    SPOJ.Visible Lattice Points(莫比乌斯反演)
    BZOJ.2301.[HAOI2011]Problem B(莫比乌斯反演 容斥)
    BZOJ.2242.[SDOI2011]计算器(扩展欧几里得 BSGS)
    Codeforces757E.Bash Plays With Functions(积性函数 DP)
    插值法
    2、Windows下安装配置Redis
  • 原文地址:https://www.cnblogs.com/zeze/p/belflod.html
Copyright © 2020-2023  润新知