Dijkstra算法是一种用于解决单源最短路径问题的经典算法,其目标是找到图中从一个源节点到所有其他节点的最短路径。
下面我将详细介绍Dijkstra算法
动图展示(取自:Python实现dijkstra算法_迪杰斯特拉算法python-CSDN博客)
算法步骤:
-
初始化: 设置一个起始节点,将其距离设置为0,其他节点的距离设置为无穷大(或者一个极大的数),并将所有节点标记为未访问。
-
选择下一个节点: 从未访问的节点中选择距离起始节点最近的节点作为当前节点。
-
更新距离: 对于当前节点的所有邻居节点,更新其到起始节点的距离。如果通过当前节点到达邻居节点的距离比当前已知的距离更短,则更新邻居节点的距离。
-
标记节点: 将当前节点标记为已访问。
-
重复步骤2-4: 重复执行步骤2到步骤4,直到所有节点都被标记为已访问。
-
输出结果: 当所有节点都被标记为已访问时,算法结束,输出从起始节点到每个节点的最短距离。
示例图表:
假设我们有以下图表表示的图,其中节点之间的边代表路径,边上的数字代表路径的权重或距离。
4 1 (A) ----- (B) ----- (C) | \ / | / | | \ 2 / | 5 / | |3 \(D) | / 3 | | \ | / \| | \ | / (F) | \ | / | |_______\| /_________| 6 6 2 5 7
现在我们以节点A作为起点运行Dijkstra算法。
- 初始化: 将起始节点A的距离设置为0,其他节点的距离设置为无穷大,表示未知。将所有节点标记为未访问。
A: 0 (visited) B: ∞ (unvisited) C: ∞ (unvisited) D: ∞ (unvisited) F: ∞ (unvisited)
-
选择下一个节点: 选择距离起始节点最近的节点A。
-
更新距离: 更新与节点A相邻的节点的距离。此时节点B、D与节点A相邻,更新它们的距离。
A: 0 (visited) B: 4 (unvisited) C: ∞ (unvisited) D: 3 (unvisited) F: ∞ (unvisited)
-
标记节点: 标记节点A为已访问。
-
重复步骤2-4: 选择距离起始节点最近的未访问节点D。
-
更新距离: 更新与节点D相邻的节点的距离。
A: 0 (visited) B: 4 (unvisited) C: 6 (unvisited) D: 3 (visited) F: ∞ (unvisited)
-
标记节点: 标记节点D为已访问。
-
重复步骤2-4: 选择距离起始节点最近的未访问节点B。
-
更新距离: 更新与节点B相邻的节点的距离。
A: 0 (visited) B: 4 (visited) C: 6 (unvisited) D: 3 (visited) F: 9 (unvisited)
-
标记节点: 标记节点B为已访问。
-
重复步骤2-4: 选择距离起始节点最近的未访问节点C。
-
更新距离: 更新与节点C相邻的节点的距离。
A: 0 (visited) B: 4 (visited) C: 6 (visited) D: 3 (visited) F: 9 (unvisited)
-
标记节点: 标记节点C为已访问。
-
重复步骤2-4: 选择距离起始节点最近的未访问节点F。
-
更新距离: 更新与节点F相邻的节点的距离。
A: 0 (visited) B: 4 (visited) C: 6 (visited) D: 3 (visited) F: 9 (visited)
- 标记节点: 标记节点F为已访问。
算法结束,最短路径的结果如下:
- 从A到B的最短距离为4
- 从A到C的最短距离为6
- 从A到D的最短距离为3
- 从A到F的最短距离为9
模板例题:求从顶点A出发的最短路径
import heapq import math # 定义图的邻接字典 graph = { "A": {"B": 5, "C": 1}, "B": {"A": 5, "C": 2, "D": 1}, "C": {"A": 1, "B": 2, "D": 4, "E": 8}, "D": {"B": 1, "C": 4, "E": 3, "F": 6}, "E": {"C": 8, "D": 3}, "F": {"D": 6} } # 初始化距离字典 def init_distance(graph, s): distance = {s: 0} for vertex in graph: if vertex != s: distance[vertex] = math.inf # 初始时,将除起始顶点外的距离都设为无穷大 return distance # Dijkstra算法实现 def dijkstra(graph, s): pqueue = [] # 优先队列,用于存储待处理的顶点 (distance, vertex) heapq.heappush(pqueue, (0, s)) # 将起始顶点放入队列,距离为0 seen = set() # 用于存储已经处理过的顶点 parent = {s: None} # 记录每个顶点的父节点 distance = init_distance(graph, s) # 初始化距离字典 while len(pqueue) > 0: pair = heapq.heappop(pqueue) dist = pair[0] # 当前顶点到起始顶点的距离 vertex = pair[1] # 当前顶点 seen.add(vertex) nodes = graph[vertex].keys() for w in nodes: if w not in seen: # 如果通过当前顶点可以获得更短的路径,则更新距离和父节点信息 if dist + graph[vertex][w] < distance[w]: heapq.heappush(pqueue, (dist + graph[vertex][w], w)) parent[w] = vertex distance[w] = dist + graph[vertex][w] return parent, distance # 调用Dijkstra算法计算从顶点"A"出发的最短路径信息 parent, distance = dijkstra(graph, "A") # 打印结果 print("父节点:", parent) print("最短路径:", distance)
想要了解更多可以参考一下博客:
https://www.cnblogs.com/goldsunshine/p/12978305.html
https://yxudong.github.io/Dijkstra-%E6%9C%80%E7%9F%AD%E8%B7%AF%E5%BE%84%E7%AE%97%E6%B3%95-Python-%E5%AE%9E%E7%8E%B0/
题单:Dijkstra 算法
右边数字为难度分。
2642. 设计可以求最短路径的图类 1811
1514. 概率最大的路径 1846
1631. 最小体力消耗路径 1948 做法不止一种
1368. 使网格图至少有一条有效路径的最小代价 2069 也可以 0-1 BFS
1786. 从第一个节点出发到最后一个节点的受限路径数 2079
1976. 到达目的地的方案数 2095
2662. 前往目标的最小代价 2154
2045. 到达目的地的第二短时间 2202 也可以 BFS
882. 细分图中的可到达节点 2328
2203. 得到要求路径的最小带权子图 2364
2577. 在网格图中访问一个格子的最少时间 2382
2699. 修改图中的边权 2874