算法简介
贝尔曼-福特算法与迪科斯彻算法类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直至得到最优解。在两个算法中,计算时每个边之间的估计距离值都比真实值大,并且被新找到路径的最小长度替代。 然而,迪科斯彻算法以贪心法选取未被处理的具有最小权值的节点,然后对其的出边进行松弛操作;而贝尔曼-福特算法简单地对所有边进行松弛操作,共|V | − 1次,其中 |V |是图的点的数量。在重复地计算中,已计算得到正确的距离的边的数量不断增加,直到所有边都计算得到了正确的路径。这样的策略使得贝尔曼-福特算法比迪科斯彻算法适用于更多种类的输入。
贝尔曼-福特算法的最多运行O(|V|·|E|)次,|V|和|E|分别是节点和边的数量)
matlab代码实现(后续会补上c++,python版本)
*核心代码
function [minD,path] = BellmanFord(w,start,terminal)
% input:
% w:图的带权邻接矩阵
% start:原点标号
% terminal:目的点标号
%
% output:
% minD:起点到终点的最短距离
% path:是一个向量,储存了重源点到目的点的路径。如果没有输入目的点
% 则第i位储存源点到节点i的最短路径上i的前驱节点
%得到必要的参数
G = sparse(w);
[u,v,c] = find(G);
V = size(w,1);
E = length(u);
f = zeros(1,V);
%算法初始化
dist = inf(1,V);
dist(start) = 0;
%主循环(算法核心)
for k = 1:(V - 1)
for e = 1:E
i = u(e);j = v(e);
if dist(j) > dist(i) + c(e)
dist(j) = dist(i) + c(e);
f(j) = i;
end
end
end
%负环检测
for e = 1:E
i = u(e);j = v(e);
if dist(j) > dist(i) + c(e)
minD = [];
path = 0;
return;
end
end
%输出
if nargin == 2
minD = dist;
path = f;
else
minD = dist(terminal);
if minD ~= inf
%重f中回退
path(1) = terminal;
forward = 1;
while path(forward) ~= start
path(forward + 1) = f(path(forward));
forward = forward + 1;
end
%调整顺序
L = length(path);
path = path(L:-1:1);
else
path = 0;%表示不可达
end
end
end
*main
w = [0 -1 4 inf inf
inf 0 3 2 2
inf inf 0 inf inf
inf 1 5 0 inf
inf inf inf -3 0];
[minD,path] = BellmanFord(w,1)
[minD,path] = BellmanFord(w,1,4)