单源最短路径
Dijkstra算法
Dijkstra算法解决的是带权重的有向图上单元最短路径问题,该算法要求所有边的权重都为非负值。
输入:有向图 G = ( V , E , W ) , V = { 1 , 2 , 3 , . . . , n } , s = 1 G=(V,E,W),V=\{1,2,3,...,n \},s=1 G=(V,E,W),V={1,2,3,...,n},s=1
输出:从s到每个顶点的最短路径
- 初始 S = { 1 } S=\{ 1\} S={1}.
- 对于 i ∈ V − S i \in V-S i∈V−S, 计算 1 到 i i i 的相对 S S S 的最短路,长度 d i s t [ i ] dist[i] dist[i].
- 选择 V − S V-S V−S 中 d i s t dist dist 值最小的 j j j , 将 j j j 加入 S S S ,修改 V − S V-S V−S 中顶点的 d i s t dist dist 值.
归纳证明思路
命题: 当算法进行到第
k
k
k 步时,对于
S
S
S 中每个结点
i
i
i ,
d
i
s
t
[
i
]
=
s
h
o
r
t
[
i
]
dist[i] = short[i]
dist[i]=short[i]
归纳基础:
k
=
1
,
S
=
{
s
}
,
d
i
s
t
[
s
]
=
s
h
o
r
t
[
s
]
=
0
k=1,S=\{s\}, dist[s] = short[s] =0
k=1,S={s},dist[s]=short[s]=0
归纳步骤:
证明:假设命题对 k k k 为真, 则对 k + 1 k+1 k+1 命题也为真.
假设命题对
k
k
k 为真,考虑
k
+
1
k+1
k+1 步算法,选择顶点
v
v
v (边
<
u
,
v
>
<u,v>
<u,v> ). 需要证明
d
i
s
t
[
v
]
=
s
h
o
r
t
[
v
]
dist[v] =short[v]
dist[v]=short[v]
若存在另一条
s
−
v
s-v
s−v 路径
L
L
L ,最后一次出
S
S
S 的顶点为
x
x
x ,经过
V
−
S
V-S
V−S 的最后一个顶点
y
y
y ,再由
y
y
y 经过一段在
V
−
S
V-S
V−S 中的路径到达
v
v
v .
在 k + 1 k+1 k+1 步算法选择顶点 v v v ,而不是 y y y , d i s t [ v ] ≤ d i s t [ y ] dist[v] \le dist[y] dist[v]≤dist[y]
令 y y y 到 v v v 的路径长度为 d ( y , v ) d(y,v) d(y,v) , d i s t [ y ] + d ( y , v ) ≤ L dist[y]+d(y,v) \le L dist[y]+d(y,v)≤L
于是 d i s t [ v ] ≤ L dist[v] \le L dist[v]≤L, 即 d i s t [ v ] = s h o r t [ v ] dist[v]=short[v] dist[v]=short[v]
时间复杂度
-
时间复杂度: O ( n m ) O(nm) O(nm)
-
算法进行 n − 1 n-1 n−1 步,每步挑选 1 个具有最小 d i s t dist dist 函数值的结点进入 S S S , 需要 O ( m ) O(m) O(m) 时间。
-
选用基于堆实现的优先队列的数据结构,可以将算法时间复杂度降到 O ( m l o g n ) O(mlogn) O(mlogn) 。
例子
python实现
V = 9 # 顶点数
# dist[v] 标记数组
dist = [False for _ in range(V)]
# distance[i] 表示从源点s到i的最短距离
distance = [float('inf') for _ in range(V)]
# weight[u][v] 表示边E=(u,v)的权值
weight = [[float("inf") for _ in range(V)] for _ in range(V)]
def dijkstra(s):
distance[s] = 0
while True:
v = -1
for u in range(V):
if not dist[u] and (v == -1 or distance[u] < distance[v]):
v = u
if v == -1:
break
dist[v] = True
for u in range(V):
distance[u] = min(distance[u], distance[v] + weight[v][u])
if __name__ == '__main__':
Inf = float('inf')
weight = [
[0, 4, Inf, Inf, Inf, Inf, Inf, 8, Inf],
[4, 0, 8, Inf, Inf, Inf, Inf, 11, Inf],
[Inf, 8, 0, 7, Inf, 4, Inf, Inf, 2],
[Inf, Inf, 7, 0, 9, 14, Inf, Inf, Inf],
[Inf, Inf, Inf, 9, 0, 10, Inf, Inf, Inf],
[Inf, Inf, 4, 14, 10, 0, 2, Inf, Inf],
[Inf, Inf, Inf, Inf, Inf, 2, 0, 1, 6],
[8, 11, Inf, Inf, Inf, Inf, 1, 0, 7],
[Inf, Inf, 2, Inf, Inf, Inf, 6, 7, 0]
]
a = int(input())
dijkstra(a)
print(distance)