Dijkstra’s Shortest Path Algorithm
- 单源最短路
- 输入:有向图 G = ( V , E ) G=(V, E) G=(V,E),要求所有边权非负,给定源点 s s s
- 输出:计算从 s s s到所有 v ∈ V v \in V v∈V的最短路径长度
- 两个假设:
- (方便起见)所有点 v v v都存在从 s s s到达之的路径
- 所有边权值非负
- BFS求解最短路?
- 只能处理边权均为1(或者所有的边权均一致)的情形
- 将非单元权值边处理成多条单元权值边?无法控制展开规模
- 算法
- 初始化
- 将源点 s s s加入到以遍历点集 X X X
- 结果数组 A [ s ] = 0 A[s]=0 A[s]=0
- 路径数据 B [ S ] B[S] B[S]为空路径(实际实现中用不到)
- 主循环
- 终止条件: X = V X = V X=V
- 考察跨域(从 X X X到 V − X V-X V−X)边中最短的一条( min v ∈ X , w ∈ V − X { A [ v ] + l v w } \min_{v \in X, w \in V-X} \{A[v] + l_{vw}\} minv∈X,w∈V−X{A[v]+lvw}) ( v ∗ , w ∗ ) (v^\ast, w^\ast) (v∗,w∗)
- 将 w ∗ w^\ast w∗加入 X X X
- 赋值 A [ w ∗ ] = A [ v ] + l v ∗ w ∗ A[w^\ast] = A[v] + l_{v^\ast w^\ast} A[w∗]=A[v]+lv∗w∗
- 赋值 B [ w ∗ ] = B [ v ∗ ] ∪ ( v ∗ , w ∗ ) B[w^\ast] = B[v^\ast] \cup (v^\ast, w^\ast) B[w∗]=B[v∗]∪(v∗,w∗)
- 初始化
- 不允许负权值边?无法保证最短路,且会出现错误
- 时间复杂度 O ( m n ) O(mn) O(mn)
- 使用数据结构来加快运行速度?及时维护“最短边”——堆
- 堆能够保证在 O ( log n ) O(\log n) O(logn)时间内得到最小值
- 不变量1:用堆维护 V − X V-X V−X中的顶点
- 不变量2:用对维护
k
e
y
[
v
]
,
v
∉
X
key[v], v \notin X
key[v],v∈/X,其为以该点为边的头的最小“分值”(不存在满足要求的边的顶点,则赋值正无穷)
- 第一轮,每个 V − X V-X V−X中的顶点更新 k e y key key值(实际就是 A A A值)
- 第二轮,得到堆中的最小值
- 维护不变量:第一个显然,第二个只需要考察与被包含顶点存在边的顶点(边要求从被包含点到该点)的
k
e
y
key
key值,为了方便实现:
- 删除顶点
- 重新计算 k e y key key值
- 以更新后的 k e y key key值重新插入该顶点
- 时间复杂度
- 堆操作 O ( log n ) O(\log n) O(logn)
- 每一个顶点需要取一次最小值 O ( n log n ) O(n \log n) O(nlogn)
- 针对每一个边,至多出发一次更新 O ( m log n ) O(m \log n) O(mlogn)
- 考虑弱连通图, n n n个 m m m相当,整体时间复杂度 O ( m log n ) O(m \log n) O(mlogn)
- 最短路时间接近排序算法