单源最短路 Bellman-Ford算法

单源最短路问题是固定一个起点s,求它到所有点的最短路的问题。

Bellman-Ford算法可以用于边权为负的情况而不像Dijkstra只适用于边权为正的情况(有负圈返回错误),但是其效率比较低。

记从起点s出发到顶点i的最短距离为的d[i] 那么
d[i] = min(d[j]+(j->i)|其中j->i属于E)

如果给定的图是DAG 那么可以用拓扑序给顶点编号,并利用这一条递推公式计算出d(DP)。
如果图中有圈,就无法依赖这样的顺序进行计算。这种情况初始d[s]=0 d[i]=INF 再不断使用这条递推关系式更新d的值。只要图中不存在负圈,更新操作就是有限的。这就是Bellman-Ford算法。

Bellman-Ford算法可以大致分为三个部分
①初始化所有d[i]为INF d[s]为0
②循环(n-1)次,在循环内部遍历所有的边,进行松弛计算。
③最后遍历所有边,检查是否存在有i指向j的边但是d[i]+(i->j) > d[j]这样的存在,如果存在,则返回false,说明图中存在可以从s到达的负圈。

实验代码
输入各个边和起点,给出从起点出发各点的最短路长度。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1000000000;
struct edge {//边
    int from,to,cost;
};
const int max_v = 1010;
edge eg[max_v];//边
int d[max_v];//d[i]表示从起点到i的距离 初始化为INF
int e,v;//边数,顶点数
int s;//起点
int main()
{
    printf("输入边数,顶点数和起点\n");
    scanf("%d%d%d",&e,&v,&s);
    for(int i = 1 ; i <= e ; i ++) scanf("%d%d%d",&eg[i].from,&eg[i].to,&eg[i].cost);

    //Bellman-Ford
    for(int i = 0 ; i < max_v ; i ++) d[i] = INF;
    d[s] = 0;
    while(1){
        bool update = false;
        for(int i = 1 ; i <= e ; i ++) {
            if(d[eg[i].from] != INF && d[eg[i].from] + eg[i].cost < d[eg[i].to]) {
                d[eg[i].to] = d[eg[i].from] + eg[i].cost;
                update = true;
            }
        }
        if(!update) break;
    }

    //输出每个点的最短路
    for(int i = 1 ; i <= v ; i ++) {
        printf("点%d的最短路为%d\n",i,d[i]);
    }

    return 0;
}

《单源最短路 Bellman-Ford算法》

下面的代码增加了显示路径的功能。用到了栈结构

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
const int INF = 1000000000;
struct edge {//边
    int from,to,cost;
};
const int max_v = 1010;
int pre[max_v];
stack<int> ss;
edge eg[max_v];//边
int d[max_v];//d[i]表示从起点到i的距离 初始化为INF
int e,v;//边数,顶点数
int s;//起点
int main()
{
    printf("输入边数,顶点数和起点\n");
    scanf("%d%d%d",&e,&v,&s);
    pre[s] = s;
    for(int i = 1 ; i <= e ; i ++) scanf("%d%d%d",&eg[i].from,&eg[i].to,&eg[i].cost);

    //Bellman-Ford
    for(int i = 0 ; i < max_v ; i ++) d[i] = INF;
    d[s] = 0;
    while(1){
        bool update = false;
        for(int i = 1 ; i <= e ; i ++) {
            if(d[eg[i].from] != INF && d[eg[i].from] + eg[i].cost < d[eg[i].to]) {
                d[eg[i].to] = d[eg[i].from] + eg[i].cost;
                pre[eg[i].to] = eg[i].from;
                update = true;
            }
        }
        if(!update) break;
    }

    //输出每个点的最短路
    for(int i = 1 ; i <= v ; i ++) {
        printf("到点%d的最短路为:\n",i);
        while(!ss.empty()) ss.pop();
        int k = i;
        while(k != pre[k]) {
            ss.push(k);
            k = pre[k];
        }
        printf("%d",s);
        while(!ss.empty()) {printf(" --> %d",ss.top());ss.pop();}
        printf("\n");
    }

    return 0;
}

《单源最短路 Bellman-Ford算法》

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