单源最短路问题是固定一个起点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;
}
时间: 2024-12-26 10:38:53