ACM_bellman ford(单源最短路)

算法作用

计算单源最短路径, 给定图和起点后, 计算这个点到其他点的最短距离, 如果起点和终点都给定了也属于这类问题
比如 :
给定图如下
《ACM_bellman ford(单源最短路)》
求1 到 其他各点的最短距离
可以计算出为 :

顶点最短距离
10
23
34
411
522

(口算的, 大概没算错吧)

算法复杂度

O(N * M) N是顶点个数, M是边数

代码实现

#include <algorithm>
#include <iostream>
using namespace std;

const int N = 10;
const int M = 20;
const int INF = 0x3f3f3f3f;

struct Edge {
    int from, to, cost;
};

int dis[N], n, m;
Edge edge[M];

void bellmanFord(int s) {
    for(int i = 0; i < n; ++i)
        dis[i] = INF;
    dis[s] = 0;

    for(int i = 1; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            Edge e = edge[j];
            dis[e.to] = min(dis[e.to], dis[e.from] + e.cost);
        }
    }
}

int cnt = 0;
void readEdge(int x, int y, int z) {
    --x, --y;
    edge[cnt].from = x;
    edge[cnt].to = y;
    edge[cnt].cost = z;
    cnt++;
}

int main() {
    readEdge(1, 2, 3);
    readEdge(3, 1, 4);
    readEdge(2, 4, 8);
    readEdge(4, 3, 14);
    readEdge(4, 5, 11);
    n = 5, m = cnt;
    bellmanFord(0);
    for(int i = 0; i < n; ++i)
        cout << dis[i] << endl;
}

算法拓展

可以用来计算负环(一个环他的所有边的权值和小于0)
有时间再更新吧, 需要用到队列, 而且要换一种姿势

算法证明

假如我求s到其他点的最短路, 不妨假设这些点为t(总共有n个顶点)
s到t最多有n-1个中间点, 假设为k[1], k[2], k[n-1],
第一次循环 找到s –> k[1]这条边, 并更新s–>k[1]的距离
第二次循环 找到k[1]–>k[2]这条边, 并更新s–>k[2]的距离
……
第n-1次循环 找到k[n-1]到t这条边, 并更新s–>t的距离

如何知道s–> k[1] , k[1] –> k[2]这些边呢? 简单, 把所有边都拿出来, 都拿去试试就行了, 在min取最小值的操作中就找到了
PS : 这种操作叫松弛操作
至于判断负环的操作….留坑

代码具体实现思路


    for(int i = 1; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            Edge e = edge[j];
            dis[e.to] = min(dis[e.to], dis[e.from] + e.cost);
        }
    }

核心就这两个for
第一个for进行n-1次松弛
第二个for进行所有边的遍历

复杂度证明

明显的两个for的复杂度, 所以O(n * m)

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/fkjslee/article/details/52029229
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞