第 25 章 全源最短路径 (All-Pairs Shortest Paths)

      +

      核心结论

      • 问题形式化:给定 n 顶点的带权有向图 \(G=(V,E)\) 与权矩阵 \(W=(w_{ij})\),求每对顶点 \((i,j)\) 的最短路径权重矩阵 \(D=(d_{ij})\),其中 \(d_{ij}=\delta(i,j)\)。

      • 直接调用单源算法:每个顶点跑一次单源算法——非负权时 Dijkstra 得 \(O(V^2 \lg V + VE)\)(斐波那契堆);含负权时 Bellman-Ford 得 \(O(V^2 E)\),对稠密图达 \(O(V^4)\)。

      • 最短路径与矩阵乘法(§25.1):DP 递推 \(l^{(m)}_{ij} = \min_k(l^{(m-1)}_{ik} + w_{kj})\),与矩阵乘法仅算子不同;用「重复平方」达到 \(\Theta(V^3 \lg V)\)。

      • Floyd-Warshall 算法(§25.2):以「中间顶点集合」\(\{1,\ldots,k\}\) 为阶段做 DP,递推 \(d^{(k)}_{ij} = \min(d^{(k-1)}_{ij}, d^{(k-1)}_{ik} + d^{(k-1)}_{kj})\),时间 \(\Theta(V^3)\),代码紧凑常数小。

      • Johnson 算法(§25.3):用 Bellman-Ford 求势函数 \(h(v)=\delta(s,v)\)(虚拟源 \(s\)),重赋权 \(\hat{w}(u,v)=w(u,v)+h(u)-h(v)\) 使所有边权非负,然后跑 V 次 Dijkstra,总时间 \(O(V^2 \lg V + VE)\)——稀疏图最快。

      • 传递闭包:用 Floyd-Warshall 把每条边权赋 1 即可;或用「逻辑 OR/AND」替代「min/+」得到仅布尔运算的版本,时间同为 \(\Theta(V^3)\)。

      本章主旨

      本章是单源最短路径(第 24 章)的全源推广,覆盖三种核心算法:基于矩阵乘法的慢速 DP(§25.1)、紧凑的 Floyd-Warshall(§25.2)、稀疏图最优的 Johnson(§25.3)。三种算法的差异在于「阶段变量」的选择:§25.1 用「边数」,§25.2 用「中间顶点集合的最大编号」,§25.3 用「势函数重赋权」。除 §25.3 外本章都用邻接矩阵表示;§25.3 是邻接表。Floyd-Warshall 因常数小而成为稠密图首选;Johnson 是稀疏图首选。

      一、核心概念

      本章围绕 6 个核心概念展开:从问题与输入约定出发,先讨论与矩阵乘法的同构 (§25.1),再给出 Floyd-Warshall (§25.2),最后介绍 Johnson 的重赋权技巧 (§25.3)。

      概念 定义 + 重要性 实现提示

      全源最短路径 (APSP)

      求每对顶点 \((i,j)\) 的最短路径权重 \(\delta(i,j)\),输出 \(n \times n\) 矩阵 \(D\);假设无负权环(否则某些 \(d_{ij} = -\infty\))。

      §25.0;输入为权矩阵 \(W\),w_{ii}=0;可同时求前驱矩阵 \(\Pi\)。

      最短路径与矩阵乘法

      DP 递推 \(l^{(m)}_{ij} = \min_k(l^{(m-1)}_{ik} + w_{kj})\);结构与标准矩阵乘法完全同构——只需把 (\cdot, +, 0) 替换为 (\min, +, \infty)。

      §25.1;EXTEND-SHORTEST-PATHS 即此运算;重复平方得 \(\Theta(V^3 \lg V)\)。

      重复平方技术

      不必逐轮扩展,可「倍增」:计算 \(W, W^2, W^4, \ldots, W^{2^{\lceil \lg(V-1)\rceil}}\);由封闭性得 \(W^{2^k} = W^{2^k-1} \circ W^{2^k-1}\)。

      §25.1;只需 \(\lceil \lg(V-1)\rceil\) 次扩展,时间从 \(O(V^4)\) 降到 \(\Theta(V^3 \lg V)\)。

      Floyd-Warshall 算法

      以「中间顶点集合」为 DP 维度:\(d^{(k)}_{ij} = \min(d^{(k-1)}_{ij}, d^{(k-1)}_{ik} + d^{(k-1)}_{kj})\);时间 \(\Theta(V^3)\),空间可优化至 \(\Theta(V^2)\)。

      §25.2;可同时构造前驱矩阵 \(\Pi^{(k)}\);可检测负环(\(d^{(n)}_{ii} < 0\))。

      重赋权 (Reweighting)

      引入势函数 \(h:V \to \mathbb{R}\),令 \(\hat{w}(u,v) = w(u,v) + h(u) - h(v)\);保持最短路径不变(引理 25.1),且若 \(h(v)=\delta(s,v)\) 则 \(\hat{w} \geq 0\)。

      §25.3;是 Johnson 算法的关键。

      Johnson 算法

      加虚拟源 \(s'\),Bellman-Ford 求 \(h(v)=\delta(s',v)\);重赋权后对每顶点跑 Dijkstra;总时间 \(O(V^2 \lg V + VE)\);含负环时 Bellman-Ford 返回 FALSE。

      §25.3;稀疏图最快;稠密图 Floyd-Warshall 更优(常数小)。

      二、详细笔记

      25.1 问题形式化与输入约定

      What:给定 \(n=|V|\) 顶点的带权有向图 \(G=(V,E)\) 与权矩阵 \(W=(w_{ij})\),求每对 \((i,j)\) 的最短路径权重,输出矩阵 \(D=(d_{ij})\) 与前驱矩阵 \(\Pi=(\pi_{ij})\)。

      Why:全源最短路径是图论核心问题——交通咨询、网络路由、社交网络中心性度量等;矩阵化输出便于后续查询。

      How

      权矩阵定义(式 25.1):

      \[w_{ij} = \begin{cases} 0 & i = j \\ w(i,j) & i \neq j \text{ 且 } (i,j) \in E \\ +\infty & i \neq j \text{ 且 } (i,j) \notin E \end{cases}\]
      • 最短路径权重 \(\delta(i,j)\):与第 24 章定义一致;负环可达时 \(\delta = -\infty\)。

      • 前驱矩阵:\(\pi_{ij} = \text{NIL}\) 或前驱顶点;行 \(i\) 描述源为 \(i\) 的最短路径树。

      • 路径打印:PRINT-ALL-PAIRS-SHORTEST-PATH 递归沿 \(\Pi\) 行回溯。

      简单直接算法(baseline):

      • 每个顶点跑一次单源:非负权用 Dijkstra(含负权用 Bellman-Ford)。

      • 总时间:\(O(V^2 \lg V + VE)\)(Dijkstra + 斐波那契堆)或 \(O(V^2 E)\)(Bellman-Ford,稠密图 \(O(V^4)\))。

      When:全源最短路径是后续 Floyd / Johnson 算法的目标;当只需少量查询时,直接调用 Dijkstra 反而更经济。

      Example:5 顶点 10 边的网络图;输出 5×5 矩阵,每格是 \(\delta(i,j)\);行 i 给出顶点 i 出发的最短路径树。

      25.2 最短路径与矩阵乘法

      What:定义 \(l^{(m)}_{ij}\) 为「i 到 j 至多 m 条边的最短路径权重」,递推 \(l^{(m)}_{ij} = \min_k(l^{(m-1)}_{ik} + w_{kj})\),时间 \(\Theta(n^4)\)(慢速版)。

      Why:建立「最短路径 ↔ 矩阵乘法」的同构——这是第一个动态规划解,可直接套用重复平方技巧优化。

      How

      递推(式 25.2):

      \[l^{(0)}_{ij} = \begin{cases} 0 & i = j \\ +\infty & i \neq j \end{cases}, \quad l^{(m)}_{ij} = \min_k\!\left(l^{(m-1)}_{ik} + w_{kj}\right)\]
      1. 终值(式 25.3):\(\delta(i,j) = l^{(n-1)}_{ij}\)(无负环时最短路径为简单路径)。

      2. EXTEND-SHORTEST-PATHS(L, W):一次扩展,时间 \(\Theta(n^3)\),是矩阵乘法的「算子替换」版:min ↔ +, + ↔ ×, +∞ ↔ 0。

      3. 重复平方:计算 \(W^{2^1}, W^{2^2}, \ldots, W^{2^{\lceil \lg(n-1)\rceil}}\);最后取不超过 \(W^{n-1}\) 的最大幂。

      4. 总时间:\(\Theta(n^3 \lg n)\)。

      When:展示「DP 与矩阵乘法的同构」是教学价值;实践中 Floyd-Warshall 因常数小更常用。

      Example:CLRS 图 25.1 的 5 顶点图,逐轮扩展得到 \(L^{(1)}=W, L^{(2)}, L^{(3)}, L^{(4)}\),最终 \(L^{(4)}\) 即最短路径权重。

      25.3 Floyd-Warshall 算法

      What:以「中间顶点集合」为阶段变量的 DP——定义 \(d^{(k)}_{ij}\) 为「所有中间顶点都在 \(\{1,\ldots,k\}\) 内的 i 到 j 最短路径权重」;递推 \(d^{(k)}_{ij} = \min(d^{(k-1)}_{ij}, d^{(k-1)}_{ik} + d^{(k-1)}_{kj})\);时间 \(\Theta(V^3)\)。

      Why:比 §25.1 简单(无需重复平方),常数极小,实践中是稠密图首选;同时可计算前驱矩阵和检测负环。

      How

      FLOYD-WARSHALL(W):

      1. \(D^{(0)} = W\)

      2. for \(k = 1\) to \(n\):

        1. let \(D^{(k)} = (d^{(k)}_{ij})\) be new \(n \times n\) matrix

        2. for \(i = 1\) to \(n\):

          1. for \(j = 1\) to \(n\):

            1. \(d^{(k)}_{ij} = \min(d^{(k-1)}_{ij}, d^{(k-1)}_{ik} + d^{(k-1)}_{kj})\)

      3. return \(D^{(n)}\)

      性质:

      • 正确性:若 k 不在最短路径上则 \(d^{(k)}_{ij} = d^{(k-1)}_{ij}\);否则路径分解为 i→k→j。

      • 空间优化:因 \(D^{(k-1)}\) 用过即丢弃,可用原地更新(仅 \(\Theta(n^2)\) 空间)。

      • 前驱矩阵 \(\Pi^{(k)}\):与 D 同时构造;式 25.6/25.7 给出递推。

      • 负环检测:若任意 \(d^{(n)}_{ii} < 0\),则存在负环(\(v \to v\) 路径权为负)。

      传递闭包(§25.2):将每条边权赋 1 跑 Floyd-Warshall,若 \(d_{ij} < n\) 则 i 可达 j;或用布尔版本把 min 替 OR、+ 替 AND,时间同为 \(\Theta(n^3)\) 但常数更小。

      When:稠密图的全源最短路径;同时求前驱矩阵;需要传递闭包;负环检测。

      Example:CLRS 图 25.4 的 5 顶点图,逐轮展示 \(D^{(k)}\) 与 \(\Pi^{(k)}\);5 轮后 \(D^{(5)}\) 即最短路径权重。

      25.4 Johnson 算法

      What:用 Bellman-Ford 求势函数 \(h(v)\),重赋权使所有边权非负,再对每个顶点跑 Dijkstra;总时间 \(O(V^2 \lg V + VE)\);含负环则返回 FALSE。

      Why:Dijkstra 在非负权时是单源最优;重赋权把负权图转为非负权图——这是「用最快算法处理最坏输入」的关键技巧。

      How

      JOHNSON(G, w):

      1. 加虚拟源 \(s'\),对所有 \(v \in V\) 加边 \((s',v)\) 权 0。

      2. if BELLMAN-FORD(G', w, s') == FALSE: return "negative cycle"

      3. for each \(v \in V\): \(h(v) = \delta(s',v)\)

      4. for each edge \((u,v) \in E\): \(\hat{w}(u,v) = w(u,v) + h(u) - h(v)\)

      5. for each \(u \in V\): // V 次 Dijkstra

        1. run DIJKSTRA(G, \hat{w}, u) 得到 \(\hat{\delta}(u, \cdot)\)

        2. for each \(v \in V\): \(d_{uv} = \hat{\delta}(u,v) + h(v) - h(u)\)

      重赋权性质(引理 25.1):

      • \(\hat{w}(p) = w(p) + h(u) - h(v)\),故 \(p\) 是否最短路径不变。

      • 取 \(h(v) = \delta(s',v)\) 时,对任何边 \((u,v)\),\(\hat{w}(u,v) = w(u,v) + \delta(s',u) - \delta(s',v)\);由三角不等式 \(\delta(s',v) \leq \delta(s',u) + w(u,v)\),故 \(\hat{w}(u,v) \geq 0\)。

      • 负环检测等价:BELLMAN-FORD 返回 FALSE ⟺ 有负环。

      When:稀疏图(\(E \ll V^2\))的全源最短路径;图含负权边但无负环。

      Example:稀疏社交网络(V=10000, E=50000):Floyd-Warshall 需要 \(O(10^{12})\),Johnson 只需 \(O(5 \times 10^5 \lg 10^4 + 5 \times 10^4)\) ≈ \(O(10^7)\)。

      三、关键图表

      核心公式对照表
      公式编号 内容

      式 25.1

      权矩阵 \(w_{ij}\) 定义

      式 25.2

      DP 递推 \(l^{(m)}_{ij} = \min_k(l^{(m-1)}_{ik} + w_{kj})\)

      式 25.3

      终值 \(\delta(i,j) = l^{(n-1)}_{ij}\)

      式 25.5

      Floyd-Warshall 递推 \(d^{(k)}_{ij} = \min(d^{(k-1)}_{ij}, d^{(k-1)}_{ik} + d^{(k-1)}_{kj})\)

      式 25.6 / 25.7

      前驱矩阵 \(\Pi^{(k)}_{ij}\) 递推

      式 25.8

      传递闭包递推(OR/AND 版本)

      式 25.9

      重赋权 \(\hat{w}(u,v) = w(u,v) + h(u) - h(v)\)

      式 25.10

      重赋权后路径权 \(\hat{w}(p) = w(p) + h(v_0) - h(v_k)\)

      引理 25.1

      重赋权不改变最短路径

      四、思维导图

      mindmap
        root((第 25 章 全源最短路径))
          问题形式化
            权矩阵W
            前驱矩阵Π
            δ(i,j)
          矩阵乘法法
            DP递推
            重复平方
            O(V³lgV)
          Floyd-Warshall
            中间顶点DP
            Θ(V³)
            传递闭包
            前驱构造
            负环检测
          Johnson算法
            虚拟源
            势函数h
            重赋权非负
            V次Dijkstra
            稀疏图最优
          算法对比
            稠密选Floyd
            稀疏选Johnson
            含负权用Bellman

      五、重点与易错点

      1. 全源 vs 单源:单源(第 24 章)从 s 出发求到所有 v;全源求每对 (u,v)。单源算法跑 V 次可解全源,但不是最优。

      2. 邻接矩阵 vs 邻接表:本章除 §25.3 外用邻接矩阵,§25.3 用邻接表。矩阵便于 DP 索引;邻接表节省空间。

      3. §25.1 的同构对照:EXTEND-SHORTEST-PATHS 是矩阵乘法的「算子替换」——min ↔ +, + ↔ ×, +∞ ↔ 0。这一对应不是巧合而是「(min, +) 半环」的体现。

      4. 重复平方的封闭性:\(W^{2^k} = W^{2^{k-1}} \circ W^{2^{k-1}}\)(算子替换意义下的乘法);故 \(\lceil \lg(n-1) \rceil\) 次扩展即可达到 \(W^{n-1}\)。

      5. Floyd-Warshall 的阶段变量是「中间顶点集合大小」,不是「边数」——这与 §25.1 不同;理解这一点是掌握 FW 的关键。

      6. Floyd-Warshall 原地更新正确(CLRS 25.2-4):因新值 \(d_{ik} / d_{kj}\) 是 k-1 轮的值,而当前轮内 (i, j) 的更新与 (i, k)/(k, j) 的更新无依赖关系(数组的同一位置会被 k 轮内多次更新但均收敛到正确值)。

      7. 前驱矩阵 \(\Pi\) 的正确性(CLRS 25.2-3):需证明 \(\Pi^{(k)}\) 对应的前驱子图 \(G_{\pi,i}\) 是最短路径树——证明 \(\pi^{(k)}_{ij} = l\) 蕴含 \(d^{(k)}_{ij} \geq d^{(k)}_{il} + w_{lj}\)。

      8. 负环检测的两种方式:Floyd-Warshall 中看对角线 \(d^{(n)}_{ii} < 0\);Johnson 看 Bellman-Ford 是否返回 FALSE。两者等价。

      9. 重赋权的「势」字来源:\(h(v)\) 物理上类比电势;\(\hat{w}(u,v) = w(u,v) + h(u) - h(v)\) 类比「电势差 = 实际值 + 起点电势 - 终点电势」。

      10. 三角不等式是重赋权非负的关键:\(\hat{w}(u,v) = w(u,v) + \delta(s',u) - \delta(s',v) \geq 0\) 由三角不等式直接推出;故 Dijkstra 可用。

      11. Johnson 不适用含负环图:Bellman-Ford 检测出负环即停止;负环导致 \(\delta(s',v) = -\infty\),无法定义 \(h(v)\)。

      12. 实践中算法选择:稠密图用 Floyd-Warshall(常数小);稀疏图用 Johnson(理论最优);非负权稀疏图用 V 次 Dijkstra。

      13. 与第 24 章的关系:Johnson 是「用 Bellman-Ford 求势」+「V 次 Dijkstra」的组合——前者代价 \(O(VE)\)(一次),后者代价 \(O(V \cdot (V \lg V + E)) = O(V^2 \lg V + VE)\)(V 次);合计 \(O(V^2 \lg V + VE)\)。

      14. 与第 26 章的衔接:最短路径树是最大流(第 26 章)的残量网络基础;Johnson 的重赋权思想在网络流的费用调整中亦有应用。