Appearance
第 10 讲 单源最短路径
本讲知识图谱
图表渲染中…
10.1 问题定义
给定有向加权图
其中路径权重是边权之和。若
常见变体:
- 单源最短路径:固定源点
到所有点。 - 单目的地最短路径:所有点到固定终点,可反向边后做单源。
- 单对最短路径:固定
。 - 全源最短路径:所有点对,见第 11 讲。
10.2 最短路径性质
最优子结构:最短路径的子路径仍是最短路径。若
三角不等式:对任意边
负权边本身不一定有问题;问题是从源点可达的负权环。如果存在可达负权环,则可以绕环无限次让路径权重趋向
10.3 松弛
所有最短路算法都围绕松弛。
初始化:
text
INITIALIZE-SINGLE-SOURCE(G, s):
for each v in V:
d[v] = infinity
parent[v] = nil
d[s] = 0松弛边
text
RELAX(u, v, w):
if d[v] > d[u] + w(u,v):
d[v] = d[u] + w(u,v)
parent[v] = ud[v] 是当前最短路径估计。松弛不会让估计低于真实最短距离;它只是在发现更短路径时降低估计。
不同算法的差别是:按什么顺序、松弛哪些边、松弛多少次。
10.4 Bellman-Ford
Bellman-Ford 可处理负权边,并能检测从源点可达的负权环。
text
BELLMAN-FORD(G, w, s):
INITIALIZE-SINGLE-SOURCE(G, s)
for i = 1 to |V|-1:
for each edge (u, v) in E:
RELAX(u, v, w)
for each edge (u, v) in E:
if d[v] > d[u] + w(u,v):
return FALSE
return TRUE为什么
正确性核心:设最短路径为
负环检测:若
时间复杂度:
10.5 DAG 最短路径
若图是 DAG,可按拓扑序松弛每条边一次。即使有负权边也没问题,因为 DAG 无环,不可能有负权环。
text
DAG-SHORTEST-PATHS(G, w, s):
topologically sort vertices of G
INITIALIZE-SINGLE-SOURCE(G, s)
for each u in topological order:
for each v in Adj[u]:
RELAX(u, v, w)拓扑序保证当处理
10.6 Dijkstra
Dijkstra 适用于所有边权非负的图。它维护一个已确定最短距离的集合
text
DIJKSTRA(G, w, s):
INITIALIZE-SINGLE-SOURCE(G, s)
S = empty set
Q = V as min-priority queue keyed by d
while Q is not empty:
u = EXTRACT-MIN(Q)
S = S union {u}
for each v in Adj[u]:
RELAX(u, v, w)正确性直觉:边权非负时,当前
复杂度:
| 实现 | 时间 |
|---|---|
| 数组/矩阵找最小 | |
| 邻接表 + 二叉堆 | |
| Fibonacci 堆 |
Dijkstra 遇到负权边可能失败,因为“当前最小估计已经最终确定”的贪心前提被破坏。
10.7 最大瓶颈路径
书面作业 2 Q5:给定边权图和
路径价值定义为:
目标:
可以把 Dijkstra 的“加法松弛 + 取最小距离”改成“取最小边权 + 最大化瓶颈”:
text
MAX-BOTTLENECK-PATH(G, s):
for each v in V:
d[v] = -infinity
parent[v] = nil
d[s] = infinity
Q = max-priority queue keyed by d
while Q is not empty:
u = EXTRACT-MAX(Q)
for each v in Adj[u]:
cand = min(d[u], w(u,v))
if d[v] < cand:
d[v] = cand
parent[v] = u
INCREASE-KEY(Q, v, d[v])这里
另一种观点:在无向图中,最大瓶颈路径可由最大生成树给出。最大生成树上任意两点路径的最小边权就是原图中的最大瓶颈值。
作业定位
- 书面作业 2 Q5:把 Dijkstra 中的
d[v] > d[u]+w(u,v)改成d[v] < max(d[v], min(d[u], w(u,v)))的瓶颈松弛逻辑,并用最大优先队列。 - 若题目问负权边是否影响,答案是瓶颈路径不做边权求和,因此负权边不会产生“负环无限降低”的问题;算法仍按边权大小比较即可。
本讲易错点
- BFS 是无权图最短路,可看作所有边权为 1 的特殊情况。
- Bellman-Ford 的第
轮不是为了继续求距离,而是检测负环。 - Dijkstra 不能处理负权边。
d[v]是估计值,不是从一开始就正确。- 最短路径前驱子图在无负环且可达时形成最短路径树,但多条最短路时树不唯一。
- 最大瓶颈路径的路径运算是
min和max,不是普通加法。
自测题
- 证明最短路径的子路径仍为最短路径。
- 写出
RELAX并解释它维护的含义。 - 为什么 Bellman-Ford 需要
轮? - 给出一个含负权边使 Dijkstra 失败的例子。
- DAG shortest path 为什么可以有负权边?
- 推导最大瓶颈路径的松弛公式。