最短路之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
原文地址:https://www.cnblogs.com/tommychok/p/5049817.html