求一个节点到其他所有节点的最短路径
思路——贪心算法:
- 假设源点为 u,将所有节点分为 S 和 V 两个集合,集合 S 中保存已经确定最短路径的节点,集合V中保存未确定最短路径的节点,源点 u 可以借助集合 S 中的节点作为中间节点到达集合 V 中的节点;定义一个数组 dist 记录源点 u 到其他节点的最短路径,一个数组 pre 记录每个节点最短路径的前驱节点。
- 初始时,集合 S 中只有源点 u,集合 V 中有其他所有节点;将 dist 数组初始化为源点 u 直接到其他节点的路径,pre 数组中所有节点的前驱初始化为源点 u。
- 每次选择当前路径最短的节点 v 加入到集合 S 中,然后更新 dist 数组和 pre 数组。假设当前路径最短的节点 v 的最短路径是 t,更新 dist 数组的公式是 min(dist, dist + t),然后将 dist 数组中路径值发生变化的节点的 pre 更新为 v。
- 直到所有节点都在集合 S 中,源点到其他所有节点的最短路径计算结束。
- 想要知道源点到一个节点 v 的最短路径上的节点,可以通过查询 pre 数组。
5.1 首先通过 pre 数组查询节点 v 的前驱节点,将该前驱节点加入栈中。
5.2 然后查询该前驱节点的前驱节点加入栈中。
5.3 重复查询前驱节点,直到找到源点 u,加入栈。
5.4 最后栈顶到栈底就是源点 u 到节点 v 的最短路径上的节点。
python代码:
import math
def dijkstra(node, graph):
node_num = len(graph)
# 初始化 dist 和 pre 数组
# 包含node本身的,因为node不一定是第一个节点,所有包含会方便很多
dist = []
pre = [-1] * node_num
for i in range(node_num):
dist.append(graph[node][i])
if graph[node][i] != math.inf:
pre[i] = node
# 初始一个数组记录节点是否加入 S
flag = [False] * node_num
flag[node] = True
# 更新最短路径
while not all(flag):
# 本次路径最小的节点加入集合 S
min_dist = math.inf
min_dist_node = None
for i in range(node_num):
if dist[i] <= min_dist and not flag[i]:
min_dist = dist[i]
min_dist_node = i
flag[min_dist_node] = True
# 更新数组 dist 和 pre
for i in range(node_num):
if flag[i]:
continue
temp, dist[i] = dist[i], min(dist[i], dist[min_dist_node] + graph[min_dist_node][i])
if temp != dist[i]:
pre[i] = min_dist_node
return dist, pre
if __name__ == '__main__':
graph = [[0, 3, 4],
[3, 0, math.inf],
[4, math.inf, 0]]
u = 1
dist, pre = dijkstra(u, graph)
pass