• 最短路之Bellman-Ford算法


    Bellman-Ford算法通过对边进行松弛操作来渐进地降低从源结点到其他结点的最短路径
    每次循环:对所有的边进行松弛操作
    循环次数:共循环n-1次(n为顶点数)
    故时间复杂度: O(VE)

    /* Bellman-Ford算法 --- 以边为存储结构 */
    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    const int maxn = 100;
    const int INF = 65535;
    
    struct Edge{
        int from, to, dist;
        Edge(){}
        Edge(int a, int b, int c) :from(a), to(b), dist(c){}
    };
    
    vector<int> G[maxn]; //G[i]-->以i为起点的边
    vector<Edge> edges;  //
    int inq[maxn], cnt[maxn];
    int d[maxn], pre[maxn];
    bool visit[maxn];
    int n, m;
    
    /************************************************************************
      Bellman-Ford算法通过对边进行松弛操作来渐进地降低从源结点到其他结点的最短路径
      每次循环:对所有的边进行松弛操作
      循环次数:共循环n-1次(n为顶点数)
      故时间复杂度: O(VE)
     ************************************************************************/
    bool bellman_ford2(int v0){
        for (int i = 0; i < n; ++i)
            d[i] = INF;
        d[v0] = 0;
        for (int i = 0; i < n; ++i){
            //对所有的边进行松弛
            for (int j = 0; j < edges.size(); ++j){
                int x = edges[j].from;
                int y = edges[j].to;
                int w = edges[j].dist;
                if (d[x] + w < d[y]){
                    d[y] = d[x] + w;
                    pre[y] = x;
                }
            }
        }
        /* 判断是否存在负环 */
        for (int j = 0; j < edges.size(); ++j){
            Edge tmp = edges[j];
            if (d[tmp.from] + tmp.dist < d[tmp.to])
                return false;
        }
        return true;
    }
    
    /* 利用队列代替循环实现 */
    bool bellman_ford(int s){
        queue<int> Q;  //Q是存储结点的队列
        memset(inq, 0, sizeof inq);
        memset(cnt, 0, sizeof cnt);
    
        for (int i = 0; i < n; ++i)
            d[i] = INF;
        d[s] = 0;
        inq[s] = true;
        Q.push(s);
    
        while (!Q.empty()){
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = 0; i < G[u].size(); ++i){
                //对边进行松弛操作
                Edge& e = edges[G[u][i]];
                if (d[u] < INF && d[e.to] > d[u] + e.dist){
                    d[e.to] = d[u] + e.dist;
                    pre[e.to] = u; 
                    if (!inq[e.to]){
                        Q.push(e.to);
                        inq[e.to] = true;
                        //若对结点的访问次数大于n则存在负环
                        if (++cnt[e.to] > n){
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
    
    
    int main()
    {
        int u, v, w, k;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; ++i){
            scanf("%d%d%d", &u, &v, &w);
            edges.push_back(Edge(u, v, w));
            k = edges.size();
            G[u].push_back(k - 1);
            //有向图可需要再加上这3行
            //edges.push_back(Edge(v, u, w));
            //k = edges.size();
            //G[v].push_back(k - 1);
        }
        if(bellman_ford(0)){
            for (int i = 0; i < n; ++i){
                printf("%d  ", d[i]);
            }
        }
        printf("
    ");
        //0-1的路径的反序
        k = 1;
        while (k != 0){
            printf("%3d ", k);
            k = pre[k];
        }
        printf("%3d
    ", k);
    
        ////以边为存储结构的输出
        //while (k != 0){
        //    printf("%3d", k);
        //    k = edges[pre[k]].from;
        //}
        //printf("%3d
    ", k);
        
        return 0;
    }
    
    /*
    
    带负权的图
    5 10
    0 1 6
    0 3 7
    1 2 5
    1 3 8
    1 4 -4
    2 1 -2
    3 2 -3
    3 4 9
    4 0 2
    4 2 7
    
    0到其他点的最短路(带负环则结束)
        dis ---> 0 2 4 7 -2
    
    */
    View Code
  • 相关阅读:
    Centos 7 快速安装 Docker
    MySQL乱码
    阿里云中linux 下svn服务器安装
    java中易错点(二)
    java中易错点(一)
    mysql5.7.24 解压版安装步骤以及遇到的问题
    linux交换分区调整
    linux之切换用户su(switch user)
    linux简单常用命令
    Yum简单使用小结
  • 原文地址:https://www.cnblogs.com/tommychok/p/5049817.html
Copyright © 2020-2023  润新知