当前位置: 代码迷 >> 综合 >> 算法 - 最短路径(三)- Bellman-Ford
  详细解决方案

算法 - 最短路径(三)- Bellman-Ford

热度:97   发布时间:2024-02-01 10:22:10.0

算法 - 最短路径(三)- Bellman-Ford

    • 前言
    • 适用前提
    • 算法思想
    • 算法分步图解及解析
      • 第一次迭代
      • 第二轮迭代
    • 关于负圈

前言

之前在学习Bellman-Ford算法的时候,看了很多国内大牛写的算法解析(图解),但总觉得有一点不对劲,于是又上YouTube上找了几个讲解Bellman-Ford算法的视频看,方恍然大悟。所以在仅把我个人对此算法的理解写下来,若要真正追求真理,还请各位动手实验与观察。

?

适用前提

没有负环的图,因为如果有负环的话可以一直在那个负环中刷出最短路径。

算法思想

假设图中有V个节点,E条边。不断松弛图中的每一条边。(松弛V-1次)

  1. 初始化:将除起点s外所有顶点的距离数组设为无穷。
  2. 迭代:遍历图中的每条边,对边的两个顶点分别进行一次松弛操作。
  3. 判断负圈:迭代V-1次之后,再次进行迭代,若还有顶点能够进行松弛,则说明存在负圈。

我们可以用距离数组d[i]来记录起点s到点i的最短距离。

算法分步图解及解析

如图,下面的有向图包含6个节点和9条边,设源点为s,初始化所有d[v]为无穷大,d[s]为0。

在这里插入图片描述

?

第一次迭代

遍历图中所有的边,首先看到E(S,A) = 5,E(S,C) = -2,所以修改d[v]的值。此时,由于d[S]和d[A]已经发生了变化,所以当我们尝试松弛其它的边时,数值都将根据当前遍历轮次之前所做的改变而改变(当然这也和边的遍历顺序有关)。在此处需要说明的一点是:边的遍历顺序其实并不重要,因为我们总是要经过V-1次迭代或是当上一次迭代所有点的距离未更新的时候我们才能得到所有点到源点的最短路径,若某条边可以松弛,那就算本轮迭代没松弛,在下一轮也会松弛。继续上图的例子,若我们按照绿色数字的顺序依次松弛每条边,在我们松弛完每一条边后,得到的结果如下图所示:

在这里插入图片描述

若我们按照其它的顺序来遍历图中所有的边,比如3、4、5、6、7、8、9、1、2,在第一轮迭代之后我们将得到完全不同的结果,如下图所示:

在这里插入图片描述

?

第二轮迭代

第二轮迭代我们仍然按照每条边编号从大到小的顺序对每条边进行遍历,得到如下结果:

在这里插入图片描述
仔细观察我们能够发现:只有在上一轮迭代中成功松弛了的点才能参与到下一轮松弛的迭代操作中。我们再来看看接着版本(2)的第一轮遍历再换一个遍历边的顺序看看结果是什么:5、7、8、9、1、2、4、6、3

在这里插入图片描述

或许大家早已有所耳闻:Bellman-Ford中迭代的真正意义在于:经历k轮迭代,我们就找到了经历k条边的最短距离。这句话说得没错,它确实揭示了迭代的实际意义,但也正是这句话,误导了我对Bellman-Ford算法的理解。

从之前的举例我们可以看到,在迭代的过程中若遍历图中每一边的顺序不同,在每次迭代后将产生完全不一样的结果。若我们以每条边按照从小到大的顺序遍历为例理解上面那句话:经历2轮迭代,我们就找到了经历2条边的最短距离。但是我们看到,d[B]=1,而这是怎么来的?S->C->A->B,这不是经历了3条边吗?为什么我们经历2轮迭代找到了经历3条边的最短距离?那是因为在那个遍历顺序中,当前迭代轮次松弛过的节点在当前迭代轮次又被使用到。而在第二个版本中,我给出遍历边的顺序巧妙避开了这一情况,从而使得在某一轮次松弛过的节点不会再被使用到。所以在第二个版本中,我们能清晰并且直观得感受到那句话:经历k轮迭代,我们就找到了经历k条边的最短距离。

那既然这句话令我产生歧义,那应该如何表达呢?

经过第k轮迭代后,对于任意节点v,如果s到v存在一条边数为k的最短路径,那么从s到v的那条边数为k的最短路径就一定能被解出来。

因为当我们每一轮迭代每松弛一个节点后,就相当于在一条路径上加上了一条边,经过k轮迭代,我们就能解出加k条边的最短路径。但由于在同一轮迭代当中,被松弛过的节点可能被松弛另一条边的时候使用到,所以我们在k轮迭代后也许就已经解出从s到v的边数大于k的最短路径(例如在第一个遍历顺序版本中第一次迭代就求出了d[A]=0,S->C->A)。

既然都说到这个份上,我想接下来的几轮迭代我也没必要画了,都是一个道理。(事实上第一个遍历顺序版本在两轮迭代后已经求出了S节点到每个点的最短路径)

关于负圈

说到负圈,必须要先说一个定理:

如果一个节点数为n的图中没有负权环,那么其任意两个节点之间一定存在最短路径,且其边数不会超过n-1。

这非常好理解,同时,这也说明了在含有n个顶点的图中,最短路径肯定是一个不可能包含回路的简单路径。因为如果存在正回路,那么去掉那个回路路径必将缩短;如果存在负回路,那最短路径为负无穷。

在这里插入图片描述

所以

  1. 在无负权环、节点数为n的图中,遵循上面的思路,我们最多只需要进行n-1轮~~迭代,就可以解决单源最短路径问题
  2. 对于节点数为n的图,如果如上进行n轮迭代,且最后一轮还能够有所改进,则说明图中必有负权环

总结起来就是,若不存在负圈,V-1条路绝对能走到最短路径;若存在负圈,路可以无限走。

  相关解决方案