前言
Bellman-Ford算法,限于资料匮乏和时间复杂度比Dijkstra算法高,包括白书在内的很多资料,都没说得太明白。对于优化后的SPFA算法也没有提及。
而且最短路问题通常是作为图论的入门问题,学习者通常没有图论基础,不知道图论的一些基本常识,看已有的资料很容易产生疑惑。其实,从Bellman-ford算法优化到SPFA算法实际上是顺理成章的。
本文旨在阐明这两个算法思想和步骤,如果有什么晦涩或者疏漏之处在所难免,烦劳读者们指出。
这里是我的个人网站:
https://endlesslethe.com/bellmanford-spfa-tutorial.html
有更多总结分享,最新更新也只会发布在我的个人网站上。
排版也可能会更好看一点=v=
Bellman-Ford算法有什么用
Bellman-Ford算法是用来解决单源最短路问题的。
在现实生活旅游途中,我们通常想知道一个景点到其他所有景点的最短距离,以方便我们决定去哪些比较近的景点。而这时候,Bellman-Ford算法就有用了。
Bellman-Ford算法的优点是可以发现负圈,缺点是时间复杂度比Dijkstra算法高。
而SPFA算法是使用队列优化的Bellman-Ford版本,其在时间复杂度和编程难度上都比其他算法有优势。
算法流程
(1)初始化:将除起点s外所有顶点的距离数组置无穷大 d[v] = INF, d[s] = 0
(2)迭代:遍历图中的每条边,对边的两个顶点分别进行一次松弛操作,直到没有点能被再次松弛
(3)判断负圈:如果迭代超过V-1次,则存在负圈
我们用距离数组d[i]来记录起点s到点i的最短距离。
看了上面的算法流程,通常我们会有四个问题:
- 什么是松弛操作
- 迭代多少次?
- 迭代的实际意义是什么?
- 为什么迭代超过v-1次就存在负圈?
直观理解松弛操作

如图,假设选取边<3,4>来进行松弛操作,那么进行两次如下操作(w为边权):
d[3] = min(d[3], d[4]+w) // 对点3
d[4] = min(d[4], d[3]+w) // 对点4
这样做的目的是让距离数组d尽量的小。
而每一次让d[i]减小的松弛操作,我们都称其“松弛成功”。
而实际中,我们使用的松弛操作可以是选取一条边,也可以是从一个点from到另一个点to。后者对应的松弛操作为:
d[to] = min(d[to], d[from] + w)
从最短路的角度来讲,如果对点3的松弛操作成功,意味着从s到4再从4到3这条路比其他从s到3的路都短,距离数组中的d[3]就是目前起点到点3的最短距离。
我们可以总结为:每一次成功的松弛操作,都意味着我们发现了一条新的最短路。
直观理解迭代
第二第三个问题实际上都是同一个问题:迭代的实际意义是什么?
这里我先给出迭代的定义:每次都遍历图中的所有边,对每条边(的两个端点)都进行松弛操作。
下面,我们以上图中的点和边为例,讲清楚迭代的实际意义:

本文详细解析Bellman-Ford与SPFA算法,阐述这两种算法如何解决单源最短路径问题,并讨论它们的应用场景与优劣。文章通过实例帮助读者理解松弛操作、迭代意义及负圈检测。
算法&spm=1001.2101.3001.5002&articleId=81232124&d=1&t=3&u=6849902278674e708b612168991e8b54)
275

被折叠的 条评论
为什么被折叠?



