单源最短路 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(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;
}

技术分享

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。