贝尔曼-福特算法(Bellman–Ford algorithm)

算法简介

贝尔曼-福特算法与迪科斯彻算法类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直至得到最优解。在两个算法中,计算时每个边之间的估计距离值都比真实值大,并且被新找到路径的最小长度替代。 然而,迪科斯彻算法以贪心法选取未被处理的具有最小权值的节点,然后对其的出边进行松弛操作;而贝尔曼-福特算法简单地对所有边进行松弛操作,共|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)
    原文作者:伊凡vnir
    原文地址: https://www.jianshu.com/p/565bfdb5d39c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞