相关笔记
- 后续笔记:23.2 Floyd-Warshall算法、23.3 稀疏图的Johnson算法
- 前置笔记:第22章_单源最短路径-章节汇总、第04章_分治策略-章节汇总
- 关联概念:22.1 Bellman-Ford算法、4.1 矩阵乘法、4.2 Strassen算法、14.2 矩阵链乘法
概览
本节介绍一种基于矩阵乘法的所有结点对最短路径(All-Pairs Shortest Paths, APSP)算法。核心思想是将最短路径问题转化为== 半环上的矩阵乘法,通过逐步扩展路径所允许的边数来逼近最短路径。由此衍生出两种算法:SLOW-ALL-PAIRS-SHORTEST-PATHS==()和 FASTER-ALL-PAIRS-SHORTEST-PATHS(),后者利用重复平方技术加速收敛。
要点列表:
- 定义 为从顶点 到顶点 的==最多包含 条边==的最短路径权重
- EXTEND-SHORTEST-PATHS 过程执行一次 矩阵乘法,将路径边数上限从 扩展到
- 慢速版本重复调用 EXTEND 次,复杂度为
- 快速版本利用重复平方,仅需 次矩阵乘法,复杂度为
- 该框架可进一步结合 Strassen 算法,将矩阵乘法的复杂度从 降低到
知识结构总览
flowchart TD A["23.1 最短路径与矩阵乘法"] --> B["问题定义"] A --> C["逐步扩展思想"] A --> D["EXTEND-SHORTEST-PATHS"] A --> E["两种算法"] A --> F["与矩阵乘法的关系"] B --> B1["APSP: 求所有顶点对的最短路径"] B --> B2["输入: 权重矩阵 W"] B --> B3["要求: w_ii = 0"] C --> C1["L^(m)_ij: 最多m条边的最短路径"] C --> C2["L^(1) = W"] C --> C3["L^(m) = L^(m-1) * W (min-plus)"] D --> D1["三重循环: i, j, k"] D --> D2["l'_ij = min(l_ij, l_ik + w_kj)"] D --> D3["等价于 (min,+) 矩阵乘法"] E --> E1["SLOW: 重复调用 |V|-1 次"] E --> E2["FAST: 重复平方 L^(1), L^(2), L^(4), ..."] E1 --> E1a["复杂度: O(V^4)"] E2 --> E2a["复杂度: O(V^3 lg V)"] F --> F1["(min,+) 半环 (Tropical Semiring)"] F --> F2["结合律保证正确性"] F --> F3["可应用 Strassen 优化"]
核心思想
核心思路
将所有结点对最短路径问题视为一种特殊的矩阵乘法。标准矩阵乘法使用 (加法, 乘法) 运算,而最短路径使用 (min, 加法) 运算。通过反复执行这种”扩展”操作,路径所允许的边数逐步增加,最终收敛到真正的最短路径。
1. APSP 问题定义
所有结点对最短路径问题(All-Pairs Shortest Paths)
输入: 一个带权有向图 ,权重函数 ,以权重矩阵 表示,其中
- 若 ,则 为边 的权重
- 若 且 ,则
- 对所有 ,要求 (从顶点到自身的空路径权重为0)
输出: 一个 矩阵 ,其中 为从顶点 到顶点 的最短路径权重
- 若从 到 不存在路径,则
- 若从 到 的路径上存在负权环,则
2. 逐步扩展性质
逐步扩展(Extending Shortest Paths)
定义 为一个 矩阵,其中 表示从顶点 到顶点 的==最多包含 条边==的最短路径权重。
关键递推关系:
展开写即为:
直觉理解: 一条从 到 的最多 条边的路径,可以看作一条从 到某个中间顶点 的最多 条边的路径,再加上最后一条边 。
为什么这个递推是正确的?
考虑从 到 的最多 条边的最短路径 。如果 有 条边,设 的倒数第二个顶点为 ,则 的前缀是从 到 的最多 条边的路径,权重为 ,加上最后一条边 的权重 。遍历所有可能的 取最小值即可。如果 少于 条边,则 已经记录了这条更短路径的权重,取 时自然会被选中。
3. EXTEND-SHORTEST-PATHS 伪代码
算法执行流程
- 对每对顶点 (i, j),将新矩阵对应位置初始化为 无穷大
- 遍历所有中间顶点 k
- 对每个 k,尝试经过 k 中转:比较当前值与 l.ik + w.kj,取较小者
- 返回新矩阵 L’
A["创建新矩阵 L'"] --> B["对每对顶点 i, j 初始化为无穷大"] B --> C["遍历中间顶点 k = 1 到 n"] C --> D{"l.ik + w.kj < 当前值?"} D -- 是 --> E["更新 l'_ij = l.ik + w.kj"] D -- 否 --> F["保持 l'_ij 不变"] E --> G{"还有下一个 k?"} F --> G G -- 是 --> C G -- 否 --> H{"还有下一对 i, j?"} H -- 是 --> B H -- 否 --> I["返回 L'"]
EXTEND-SHORTEST-PATHS(L, W)
1 n = L.rows
2 let L' = (l'_{ij}) be a new n x n matrix
3 for i = 1 to n
4 for j = 1 to n
5 l'_{ij} = ∞
6 for k = 1 to n
7 l'_{ij} = min(l'_{ij}, l_{ik} + w_{kj})
8 return L'
EXTEND-SHORTEST-PATHS 的理解
三重循环的结构:外层遍历目标顶点对,内层遍历所有可能的中间顶点。对每对顶点,尝试”经过中间顶点中转”能否得到更短的路径。
与标准矩阵乘法的对应:标准矩阵乘法中用求和与乘法,而此处将求和替换为 min,将乘法替换为 加法。
4. 引理23.1(EXTEND 的正确性)
引理23.1
给定权重矩阵 ,其中对所有 有 。令 (当 时),(当 时)。则对 ,矩阵 中的元素 等于从顶点 到顶点 的==最多包含 条边==的最短路径权重。
引理23.1 的证明
采用数学归纳法对 进行归纳。
基础情况():
- ,即
- 从 到 的最多1条边的路径只有两种情况:
- 空路径(仅当 ):权重为
- 单条边 (仅当 ):权重为
- 不存在边 且 :权重为
- 因此 确实等于最多1条边的最短路径权重
- 基础情况成立
归纳步骤:
- 归纳假设: 对某个 , 等于从 到 的最多 条边的最短路径权重
- 要证: 等于从 到 的最多 条边的最短路径权重
- 由 EXTEND-SHORTEST-PATHS 的定义:
- 考虑从 到 的最多 条边的最短路径 :
- 情况1: 最多有 条边。由归纳假设, 已经是这条路径的权重。此时取 ,有 ,因此 操作不会遗漏这种情况
- 【路径分解(拆分为边子路径+最后一条边)】 情况2: 恰好有 条边。设 为 的倒数第二个顶点。则 可以分解为:从 到 的最多 条边的子路径 ,加上最后一条边 。由归纳假设, 的权重为 ,因此 的权重为 。 操作遍历所有 ,必然能找到使 最小的那个
- 综合两种情况, 确实等于最多 条边的最短路径权重
- 归纳步骤成立
结论: 由数学归纳法,引理23.1对所有 成立。
5. SLOW-ALL-PAIRS-SHORTEST-PATHS
算法执行流程
- 初始化 L^(1) = W(权重矩阵)
- 依次计算 L^(2), L^(3), …, L^(n-1),每次用 EXTEND-SHORTEST-PATHS 扩展
- 每次扩展将路径边数上限从 m-1 增加到 m
- 返回 L^(n-1) 作为所有结点对最短路径
A["初始化 L^(1) = W"] --> B["令 m = 2"] B --> C["L^(m) = EXTEND-SHORTEST-PATHS(L^(m-1), W)"] C --> D{"m <= n - 1?"} D -- 是 --> E["m = m + 1"] E --> C D -- 否 --> F["返回 L^(n-1)"]
SLOW-ALL-PAIRS-SHORTEST-PATHS(W)
1 n = W.rows
2 L^(1) = W
3 for m = 2 to n - 1
4 L^(m) = EXTEND-SHORTEST-PATHS(L^(m-1), W)
5 return L^(n-1)
SLOW-ALL-PAIRS-SHORTEST-PATHS
正确性: 由引理23.1, 等于从 到 的最多 条边的最短路径权重。由于简单路径最多包含 条边( 个顶点的路径最多 条边),若图中不存在从 可达的负权环,则最短路径一定是简单路径,因此 就是真正的最短路径权重。
时间复杂度:
- EXTEND-SHORTEST-PATHS 的三重循环耗时
- 共调用 次 EXTEND(从 到 )
- 总时间: ==== =
空间复杂度: (存储两个 矩阵 和 )
6. FASTER-ALL-PAIRS-SHORTEST-PATHS(重复平方)
算法执行流程
- 初始化 L^(1) = W
- 令 m = 1,重复倍增:L^(2m) = L^(m) x L^(m)(Min-Plus 乘法)
- 每次迭代将路径边数上限翻倍
- 直到 2m >= n - 1 时停止,返回最终矩阵
A["初始化 L^(1) = W, m = 1"] --> B{"m < n - 1?"} B -- 是 --> C["L^(2m) = EXTEND-SHORTEST-PATHS(L^(m), L^(m))"] C --> D["m = 2m"] D --> B B -- 否 --> E["返回 L^(m)"]
FASTER-ALL-PAIRS-SHORTEST-PATHS(W)
1 n = W.rows
2 L^(1) = W
3 m = 1
4 while m < n - 1
5 L^(2m) = EXTEND-SHORTEST-PATHS(L^(m), L^(m))
6 m = 2m
7 return L^(m)
FASTER-ALL-PAIRS-SHORTEST-PATHS
核心思想——重复平方(Repeated Squaring):
- 注意到 ,即 可以通过将 与自身做 乘法得到
- 这类似于快速幂的思想:不是一步一步从 推到 ,而是指数级跳跃:
正确性: 与 的 乘法等价于 。因为: 这表示从 到 先走最多 条边到 ,再从 走最多 条边到 ,总共最多 条边。
时间复杂度:
- 每次迭代执行一次 EXTEND-SHORTEST-PATHS,耗时
- while 循环执行 次
- 总时间: ==== =
空间优化: 原始算法需要存储 个矩阵,空间为 。可以只保留两个矩阵交替使用,将空间降至 。
7. 与矩阵乘法的深层关系
半环与标准矩阵乘法
定义热带半环(Tropical Semiring):
- “加法”运算为 (取最小值),单位元为
- “乘法”运算为 (普通加法),单位元为
在此半环上定义矩阵乘法:
这恰好就是 EXTEND-SHORTEST-PATHS 执行的操作。因此:
- ( 在 半环上的 次幂)
- 给出所有结点对的最短路径权重
与标准矩阵乘法的类比:
标准矩阵乘法 最短路径矩阵乘法 单位矩阵 (对角线为1) 单位矩阵 (对角线为0) 结合律成立 结合律成立 = 自乘 次 = 自乘 次
8. 与 Strassen 算法的结合
利用 Strassen 算法加速 APSP
既然 APSP 可以归约为 半环上的矩阵乘法,而 Strassen 算法将标准矩阵乘法从 优化到 ,那么能否直接套用?
关键观察: Strassen 算法只依赖于加法和乘法的分配律和结合律,不依赖于具体的数值运算。 半环同样满足这些代数性质( 对 满足分配律:),因此 Strassen 的分治策略可以直接移植。
将 Strassen 应用于 矩阵乘法:
- 将 Strassen 中的 替换为 ,将 替换为
- 每次递归将 矩阵乘法分解为 7 个 矩阵乘法
- 复杂度从 降低到
理论意义: 这是 APSP 问题的一个次立方算法。虽然实际中 23.2 Floyd-Warshall算法 的 常数因子更小,但 Strassen 方法证明了 APSP 可以突破立方复杂度。
补充理解与拓展
Min-Plus 矩阵乘法(Tropical Semiring)的广泛应用
矩阵乘法不仅用于最短路径,在许多领域都有重要应用:
- 运筹学与调度问题:关键路径法(CPM)中,项目完成时间可以通过 矩阵乘法计算(与 对偶)
- 语言与自动机理论:有限自动机的语言接受问题可以表示为 半环上的矩阵乘法,而最短路径是 的特例
- 图像处理:形态学运算(膨胀、腐蚀)可以用 和 矩阵运算表示
- 生物信息学:序列比对中的动态规划可以看作 矩阵乘法的变体
为什么叫”Tropical”(热带)? 这个名字来自巴西数学家 Imre Simon,他在圣保罗大学(位于热带地区)对这种代数结构做了大量研究。 半环也被称为”min-plus 代数”或”热带代数”。
来源:Min-plus algebra (Wikipedia); Butkovic, “Max-linear Systems: Theory and Algorithms” (Springer, 2010)
重复平方技术的通用性
重复平方(Repeated Squaring)是一种通用的算法加速技术,不仅限于最短路径:
应用场景 操作 加速效果 快速幂 的计算 APSP(本节) 矩阵幂 传递闭包 布尔矩阵幂 Fibonacci 数 矩阵幂 核心思想一致:利用运算的结合律,将线性次数的迭代压缩为对数次数。在 APSP 中,关键洞察是 ,即两次 步扩展等价于一次 步扩展。
易混淆点与辨析
混淆:逐步扩展矩阵乘法 vs Floyd-Warshall 算法
两种算法都解决 APSP 问题,但扩展方式完全不同:
维度 逐步扩展(本节) Floyd-Warshall(23.2节) 扩展维度 按边数扩展: 按中间顶点集合扩展: 递推公式 慢速复杂度 快速复杂度 (重复平方) (就地更新) 直觉 ”路径最多能走几步" "路径最多能经过哪些中间点” 关键区别: 逐步扩展的”慢速”版本是 ,而 Floyd-Warshall 直接就是 。逐步扩展需要借助重复平方才能达到 ,仍比 Floyd-Warshall 多一个 因子。但逐步扩展的理论价值在于揭示了 APSP 与矩阵乘法的深刻联系。
混淆: vs 的差异来源
- (SLOW版本): EXTEND-SHORTEST-PATHS 本身是 (三重循环),调用 次,所以
- (FAST版本): 同样是 的 EXTEND,但只调用 次(重复平方),所以
- 加速的核心是利用了结合律:,一次乘法将路径边数上限翻倍
混淆: 与 的含义
- :从 到 的最多 条边的最短路径权重(本节)
- :从 到 的所有中间顶点编号不超过 的最短路径权重(23.2节)
- 两者刻画路径的方式不同,不要混淆
习题精选
| 题号 | 题目描述 | 难度 |
|---|---|---|
| 23.1-1 | 对图25.2中的加权有向图运行 SLOW-ALL-PAIRS-SHORTEST-PATHS 和 FASTER-ALL-PAIRS-SHORTEST-PATHS,展示每次迭代得到的矩阵 | ⭐⭐ |
| 23.1-2 | 为什么要求对所有 有 ? | ⭐ |
| 23.1-3 | 矩阵 (对角线为0,其余为 )在常规矩阵乘法中对应什么? | ⭐ |
| 23.1-4 | 证明 EXTEND-SHORTEST-PATHS 定义的矩阵乘法满足结合律 | ⭐⭐⭐ |
| 23.1-5 | 如何将单源最短路径问题表示为矩阵与向量的乘积? | ⭐⭐ |
| 23.1-6 | 如何从完成的最短路径权重矩阵 在 时间内计算出前驱矩阵 ? | ⭐⭐ |
23.1-1 解答
目标: 对图25.2中的加权有向图分别运行两种算法。
初始权重矩阵 :
SLOW-ALL-PAIRS-SHORTEST-PATHS 的迭代过程:
:
:
:
:
FASTER-ALL-PAIRS-SHORTEST-PATHS 的迭代过程(重复平方):
:与 SLOW 的 相同
:,结果与 SLOW 的 相同
:,结果与 SLOW 的 相同(因为 ,,所以 已经收敛到最终答案)
观察: 两种算法得到相同的最终结果,但 FAST 版本只需 3 次迭代(),而 SLOW 版本需要 4 次迭代()。对于更大的图,差异会更加显著。
23.1-2 解答
目标: 解释为什么要求 。
原因分析:
语义一致性: 从顶点 到自身的最短路径是空路径(不经过任何边),其权重为 0。如果 ,则 ,与”空路径权重为0”矛盾。
负权环检测: 如果存在 ,意味着存在一个从 到 的负权环(自环)。如果 ,则 ,但空路径权重为 0,这会导致 中的对角线元素不正确。
EXTEND 的正确性依赖: 在 EXTEND-SHORTEST-PATHS 中,当 时,计算 。如果 ,则 ,这意味着”不经过任何中间顶点”的情况不会被正确处理。具体来说,取 时, 会偏离 的真实值,导致 产生错误结果。
结论: 保证了 (单位矩阵)在 半环中充当正确的单位元角色,同时确保了 EXTEND 操作的正确性。
23.1-3 解答
目标: 确定 在常规矩阵乘法中的对应物。
在 半环中, 是单位矩阵:
- 对角线元素为 ,即 半环中”乘法”()的单位元
- 非对角线元素为 ,即 半环中”加法”()的单位元
在标准矩阵乘法 中,对应的单位矩阵为:
其中对角线为 ( 的单位元),非对角线为 ( 的单位元)。
结论: 是 半环上的单位矩阵,对应标准矩阵乘法中的==单位矩阵 ==。
23.1-4 解答
目标: 证明 EXTEND-SHORTEST-PATHS 定义的矩阵乘法满足结合律。
证明:
需要证明:,其中 表示 矩阵乘法。
考虑等式左边 :
【交换律()】 关键步骤是第三行到第四行的交换:(两个 可以交换顺序),【提出常数(不依赖可提到外)】 以及第五行将 提到内层 外面(因为 不依赖于 )。
因此 ,结合律成立。
23.1-6 解答
目标: 从完成的最短路径权重矩阵 在 时间内计算前驱矩阵 。
算法思路:
对每个源顶点 ,需要构建以 为根的最短路径树。对每个目标顶点 ,找到 在最短路径上的前驱顶点。
具体方法: 对固定的 和 ,前驱 是满足 的顶点 (即最短路径上 的前一个顶点)。
算法:
COMPUTE-PREDECESSOR-FROM-L(L, W) 1 n = L.rows 2 let Pi = (pi_{ij}) be a new n x n matrix 3 for i = 1 to n 4 for j = 1 to n 5 if i == j 6 pi_{ij} = NIL 7 else 8 pi_{ij} = NIL 9 for k = 1 to n 10 if k != j and L[i][k] + W[k][j] == L[i][j] 11 pi_{ij} = k 12 break 13 return Pi复杂度分析: 外层两重循环 ,内层搜索 ,总计 。
注意: 这里使用的是原始权重矩阵 而非 来检查最后一条边,因为我们需要找到最短路径上 的直接前驱(通过一条边相连的顶点)。
视频学习指南
| 资源 | 主题 | 链接 | 说明 |
|---|---|---|---|
| MIT 6.006 Lecture 16 | Graph APSP | https://www.youtube.com/watch?v=KXzJ7dOqTqI | MIT公开课,涵盖APSP的矩阵乘法方法 |
| Abdul Bari | Floyd-Warshall & APSP | https://www.youtube.com/watch?v=oNI0rf2P9gE | 直观的逐步演示 |
| WilliamFiset | Floyd Warshall | https://www.youtube.com/watch?v=4OQeClyHbew | 包含代码实现与复杂度分析 |
| GeeksforGeeks | APSP | https://www.geeksforgeeks.org/floyd-warshall-algorithm-dp-16/ | 文字+图示,适合对照学习 |
教材原文
CLRS 第4版 23.1节原文
To solve the all-pairs shortest-paths problem on an input graph , we need to compute the shortest-path weight for every pair of vertices . We can enumerate all pairs, running a single-source shortest-paths algorithm from each vertex, but doing so takes time, where is the running time of the single-source algorithm. If we use Bellman-Ford, which runs in time, the total time becomes . If all edge weights are nonnegative, we can use Dijkstra’s algorithm, which runs in time with a binary min-heap, yielding a total time of .
This section presents two dynamic-programming algorithms for the all-pairs shortest-paths problem. The first, which we call SLOW-ALL-PAIRS-SHORTEST-PATHS, computes the shortest-path weights by exploiting the relationship between the all-pairs shortest-paths problem and the matrix multiplication problem. The second, FASTER-ALL-PAIRS-SHORTEST-PATHS, computes the same result more quickly by using the technique of “repeated squaring.”
参见Wiki
- 所有结点对最短路径 — 所有结点对最短路径问题概述
- Floyd-Warshall算法 — Floyd-Warshall 算法详解