Archipelago

Lec 12Bellman–Ford 算法

讲义完成更新于 2026-09-16

Lec 12 Bellman–Ford 算法

资料依据:课程视频与 transcript · Lecture notes

TL;DR

  • 在没有可达负权环时,任意最短路径都可选为至多含 ∣V∣−1|V|-1 条边的简单路径。
  • Bellman–Ford 按“最多使用 kk 条边”组织动态规划,重复扫描所有边,在 O(∣V∣∣E∣)O(|V||E|) 时间内求得单源最短路径。
  • 在完成 ∣V∣−1|V|-1 轮后仍能改善的可达边给出负权环见证,因而算法同时具备求解和拒绝无界实例的能力。

复习

Bellman–Ford 算法图示 1

给定无向图 G, 返回 G 是否包含负权重环?

Solution: 如果 G 中存在一条负权重边,则返回 Yes,时间复杂读 O(|E|)

因此本讲中,讨论限制为有向图。

给定运行时间为 O(|V|(|V| + |E|))的 SSSP 算法 A,展示如何在它 O(|V||E|)时间内解决 SSSP 问题。

Solution:

  • 运行 BFS 或者 DFS 找到从 s 可达的顶点,时间复杂度为 O(|E|)

  • 将每个 s 不可达的顶点标记为θ(s,v)=∞\theta(s, v) = \infty,时间复杂度为 O(|V|)

  • 构建图 G’=(V', E'),其中仅包含从 s 可达的顶点,时间复杂度为 O(|V|+|E|)

  • 在 G‘上从 s 运行 A

  • G'是连通的,所以|V'| = O(|E'|) = (|E|),因此 A 的运行时间是 O(|V||E|)

简单最短路径

  • 如果图中包含环和负权重,可能会有负权重环
  • 如果图中不包含负权重环,则最短路径是简单的
  • 断言 1:如果δ(s,v)\delta(s, v)是有限的,则存在一条道 v 的简单路径。
  • 证明: 通过反证法
    • 假设没有简单的最短路径,设π\pi为具有最少顶点的简单路径
    • π\pi不是简单路径,所以π\pi中存在环 C; C 具有非负权重(否则δ(s,v)=−∞\delta(s, v) = -\infty)
    • 去掉π\pi中的 C 形成路径π′\pi',其顶点更少且权重 w(π′\pi') ≤\le w(π\pi)
  • 由于简单路径不能重复顶点,有限的最短路径最多包含|V| - 1 条边。

负权重环见证者

  • k-edge 距离δk(s,v)\delta_k(s, v): 从 s 到 v 使用不超过 k 条边的任意路径的最小权重
  • 思路: 计算所有的v∈Vv\in V的δ∣V∣−1(s,v)和δ∣V∣(s,v)\delta_{|V|-1}(s, v) 和 \delta_{|V|}(s, v)
    • 如果δ(s,v)≠−∞\delta(s,v) \neq -\infty则δ(s,v)=δ∣V∣−1(s,v)\delta(s,v) = \delta_{|V|-1}(s, v), 因为最短路径是简单的(或者不存在)
    • 如果δ∣V∣(s,v)<δ∣V∣−1(s,v)\delta_{|V|}(s, v) \lt \delta_{|V|-1}(s, v)
      • 存在一条更短的非简单路径 v,所以δ∣V∣(s,v)=−∞\delta_{|V|}(s, v) = -\infty
      • 成 v 为(负环)见证者
      • 但是可能存在最短路径权重为−∞-\infty但不是见证者的顶点
  • 断言 2: 如果δ(s,v)=−∞\delta(s,v) = -\infty,则 v 可从一个见证者到达
  • 证明: 只需证明: 从 s 可到达的每个负权重环都包含一个见证者
    • 考虑一个从 s 可到达的负权重环 C
    • 对于 C 中的每个顶点 v,令 v'为 v 在 C 中的前驱,其中∑v∈Cw(v′,v)<0\sum_{v∈C}w(v′,v)<0
    • 则δ∣V∣(s,v)≤δ∣V∣−1(s,v′)+w(v′,v)\delta_{|V|}(s, v) \leq \delta_{|V|-1}(s, v') + w(v', v)(右边为某条不超过|V|个顶点的路径的权重
    • 所以δ∣V∣(s,v)≤δ∣V∣−1(s,v′)+w(v′,v)<δ∣V∣−1(s,v)\delta_{|V|}(s, v) \leq \delta_{|V|-1}(s, v') + w(v', v) \lt \delta_{|V|-1}(s, v)
    • 如果 C 中不包含见证者,则对所有v∈Cv\in C,满足δ∣V∣(s,v)≥δ∣V∣−1(s,v)\delta_{|V|}(s, v) \ge \delta_{|V|-1}(s, v),这就产生了矛盾

Bellman-Ford 算法

原始的 Bellman-Ford 算法较为简单,但是功能稍弱。它仅使用 O(|V|)的空间,以相同的时间复杂度解决 SSSP 问题,但是只能检测负权环是否存在。它基于松弛框架。算法很直接,首先初始化距离估计,然后再图中进行∣V∣−1|V| - 1轮松弛操作。这个算法的主张是,如果图中不存在负权环,在算法结束时,对于所有的顶点v∈Vv\in V, 有d(s,v)=δ(s,v)d(s, v) = \delta(s,v),否则,如何仍有任何边可松弛,则图中包含一个负权环

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

该算法的总体结构与通用的松弛范式相同,但吸纳值了可以处理边的顺序。具体来说,算法在∣V∣−1|V| - 1 轮次中,松弛了图中的每条边,以下引理证明了该算法的正确性。

【引理】在 Bellman-Ford 算法的第 i 轮松弛结束时,对于任意顶点 v,如果从 s 到 v 的最短路径经过至多 i 条边,那么d(s,v)=δ(s,v)d(s, v) = \delta(s, v)

证明: 对 i 轮的归纳证明。 在算法开始时,唯一从 s 出发且经过至多 0 条边的顶点是 s,基本情况成立,假设在第i−1i-1轮结束时命题成立。令 v 是从 s 到 v 的最短路径经过至多 i 条边的顶点。如果 v 有一条经过至多 i - 1 条边的最短路径,那么在第 i 轮之前 d(s,v)=δ(s,v)d(s, v) = \delta(s,v),并且在第 i 轮结束时仍然成立,这依据是上界性质

我的理解

我的理解

Bellman–Ford 可以被看作对“路径边数”的动态规划。这个视角同时解释了为何要做 ∣V∣−1|V|-1 轮,以及为何多做一轮就能检测负权环。