Lec 12Bellman–Ford 算法
Lec 12 Bellman–Ford 算法
资料依据:课程视频与 transcript · Lecture notes
TL;DR
- 在没有可达负权环时,任意最短路径都可选为至多含 条边的简单路径。
- Bellman–Ford 按“最多使用 条边”组织动态规划,重复扫描所有边,在 时间内求得单源最短路径。
- 在完成 轮后仍能改善的可达边给出负权环见证,因而算法同时具备求解和拒绝无界实例的能力。
复习

给定无向图 G, 返回 G 是否包含负权重环?
Solution: 如果 G 中存在一条负权重边,则返回 Yes,时间复杂读 O(|E|)
因此本讲中,讨论限制为有向图。
给定运行时间为 O(|V|(|V| + |E|))的 SSSP 算法 A,展示如何在它 O(|V||E|)时间内解决 SSSP 问题。
Solution:
-
运行 BFS 或者 DFS 找到从 s 可达的顶点,时间复杂度为 O(|E|)
-
将每个 s 不可达的顶点标记为,时间复杂度为 O(|V|)
-
构建图 G’=(V', E'),其中仅包含从 s 可达的顶点,时间复杂度为 O(|V|+|E|)
-
在 G‘上从 s 运行 A
-
G'是连通的,所以|V'| = O(|E'|) = (|E|),因此 A 的运行时间是 O(|V||E|)
简单最短路径
- 如果图中包含环和负权重,可能会有负权重环
- 如果图中不包含负权重环,则最短路径是简单的
- 断言 1:如果是有限的,则存在一条道 v 的简单路径。
- 证明: 通过反证法
- 假设没有简单的最短路径,设为具有最少顶点的简单路径
- 不是简单路径,所以中存在环 C; C 具有非负权重(否则)
- 去掉中的 C 形成路径,其顶点更少且权重 w() w()
- 由于简单路径不能重复顶点,有限的最短路径最多包含|V| - 1 条边。
负权重环见证者
- k-edge 距离: 从 s 到 v 使用不超过 k 条边的任意路径的最小权重
- 思路: 计算所有的的
- 如果则, 因为最短路径是简单的(或者不存在)
- 如果
- 存在一条更短的非简单路径 v,所以
- 成 v 为(负环)见证者
- 但是可能存在最短路径权重为但不是见证者的顶点
- 断言 2: 如果,则 v 可从一个见证者到达
- 证明: 只需证明: 从 s 可到达的每个负权重环都包含一个见证者
- 考虑一个从 s 可到达的负权重环 C
- 对于 C 中的每个顶点 v,令 v'为 v 在 C 中的前驱,其中
- 则(右边为某条不超过|V|个顶点的路径的权重
- 所以
- 如果 C 中不包含见证者,则对所有,满足,这就产生了矛盾
Bellman-Ford 算法
原始的 Bellman-Ford 算法较为简单,但是功能稍弱。它仅使用 O(|V|)的空间,以相同的时间复杂度解决 SSSP 问题,但是只能检测负权环是否存在。它基于松弛框架。算法很直接,首先初始化距离估计,然后再图中进行轮松弛操作。这个算法的主张是,如果图中不存在负权环,在算法结束时,对于所有的顶点, 有,否则,如何仍有任何边可松弛,则图中包含一个负权环
def bellman_ford(Adj, w, s):
# 初始化
infinity = float('inf')
d = [infinity for _ in Adj]
parent = [None for _ in Adj]
d[s], parent[s] = 0, s
V = len(Adj)
for k in range(V-1):
for u in range(V):
for u in Adj(u):
try_to_relax(Adj, w, d, parent, u, v)
for u in range(V):
for v in Adj[u]:
if d[v] > d[u] + w(u, v):
raise Exception('Ack! There is a negative weight cycle!')
return d, parent
该算法的总体结构与通用的松弛范式相同,但吸纳值了可以处理边的顺序。具体来说,算法在轮次中,松弛了图中的每条边,以下引理证明了该算法的正确性。
【引理】在 Bellman-Ford 算法的第 i 轮松弛结束时,对于任意顶点 v,如果从 s 到 v 的最短路径经过至多 i 条边,那么
证明: 对 i 轮的归纳证明。 在算法开始时,唯一从 s 出发且经过至多 0 条边的顶点是 s,基本情况成立,假设在第轮结束时命题成立。令 v 是从 s 到 v 的最短路径经过至多 i 条边的顶点。如果 v 有一条经过至多 i - 1 条边的最短路径,那么在第 i 轮之前 ,并且在第 i 轮结束时仍然成立,这依据是上界性质
我的理解
我的理解
Bellman–Ford 可以被看作对“路径边数”的动态规划。这个视角同时解释了为何要做 轮,以及为何多做一轮就能检测负权环。