一、简述
一种应用贪心策略的单源最短路径算法, 计算源点到所有结点的最短路径,主要解决带权重的图结构。
二、核心思想
- 初始: 确认源点的最短路径估值为0,其余的顶点的最短路径估值均为无穷大。
(由于源点到源点,显然是最自然最短路径,而源点到其他顶点的距离尚不知道,故假设为无穷大,或者说是无法达到) - 迭代: 每次从所有点中锁定最短路径估值最小的顶点(前面已被锁定的顶点不再参与排序),对该顶点进行松弛操作。
- 终止: 不断进行步骤2直到所有顶点都被锁定。
最短路径估值: 源点 s s s到 u u u的最短路径估计值
u u u: 是除了源点 s s s外的顶点
松弛操作
若 s s s到 u u u的最短路径已经确定,则调整 u u u的邻接点 v v v( v ∈ u . A d j ) v \in u.Adj) v∈u.Adj)的最短路径估值。
- 如果存在源点 s s s到 v v v的最短路径估值大于源点 s s s到 u u u再到 v v v的最短路径估值,则将 v v v点的前驱设为 u u u,并将 v v v的最短路径估值更新为源点 s s s到 u u u再到 v v v的最短路径估值
u u u: 是除了源点 s s s外的顶点
v v v: u u u的邻接点
u . A d j u.Adj u.Adj: u u u的邻接顶点集合
作用: 通过松弛操作确保最短路径的边界 v v v的最短路径估值尽可能小。因为我们已经确认源点到 v v v前驱的最短路径,那么 s s s到 v v v的最短路径,要么本身已经被确认(即源点无法达到 v v v或者 v v v就是源点)为最短路径,要么是基于其前驱的路径上的。当然,为了上面的说法能成立,该算法仅能用于边的权值不可为负权的图。
三、代码实现
import math
# 节点个数
vex_num = 6
# 邻接矩阵,用于存储边的权值
matrix = [[float('inf')] * vex_num for i in range(vex_num)]
# 记录已被确认最短距离的点
is_fixed = [False] * vex_num
# 记录可达点最短距离
dis = [float('inf')] * vex_num
# init matrix(一个用例测试)
matrix[0][2] = 10
matrix[0][4] = 30
matrix[0][5] = 100
matrix[1][2] = 5
matrix[2][3] = 50
matrix[3][5] = 10
matrix[4][5] = 60
matrix[4][3] = 20
# 设置起点
start_vex = 0
# init dis
for i in range(vex_num):
dis[i] = matrix[start_vex][i]
# init fix list
is_fixed[start_vex] = True
# 第i个元素表示,第i个节点的前驱节点标号
path = [None] * vex_num
# init path
for i in range(vex_num):
if not math.isinf(matrix[start_vex][i]):
path[i] = start_vex
# 获取尚未被确定的最短距离的点
def get_min_dis():
vex = None
min = float('inf')
for i in range(vex_num):
if is_fixed[i] == False and dis[i] < min:
min = dis[i]
vex = i
return vex
def algo():
while True:
vex = get_min_dis()
# 所有点都已经固定
if(vex is None):
break
is_fixed[vex] = True
# 对vex进行松弛
for i in range(vex_num):
# 获取vex邻接节点
power = matrix[vex][i]
if math.isinf(power):
continue
adjvex = i
if dis[adjvex] > dis[vex] + power:
dis[adjvex] = dis[vex] + power
path[adjvex] = vex
algo()
# 打印可达路径
for i in range(vex_num):
msg = []
j = i
while path[j] is not None:
j = path[j]
msg.append(j)
msg.reverse()
msg.append(i)
print(i, msg)