已发布·持续改进
Algorithm
用 Dijkstra、Bellman-Ford 和 Floyd-Warshall 求最短路径,用 Kruskal 和 Prim 构造最小生成树。
最短路径问题是在带权图中寻找两个顶点之间权值总和最小的路径。最小生成树(MST)是在无向图中以不形成环的方式连接所有顶点、且权值总和最小的边集合。本主题的核心算法包括 Dijkstra、Bellman-Ford、Floyd-Warshall、0-1 BFS、Kruskal 和 Prim。
这些算法运行在地图导航、OSPF 和 RIP 等路由协议、游戏寻路、电缆与管道网络设计以及聚类分析之中。它们也是技术面试和算法竞赛的常考内容,因为可以考察你能否把问题建模成图,并根据权值的特点(是否有负权、是否只有 0 和 1、图是稀疏还是稠密)选出合适的算法。
建议先熟悉 BFS 和优先队列(堆)。然后理解所有最短路径算法共用的松弛(relaxation)操作,并在小图上手动模拟一遍 Dijkstra。接着弄清楚为什么出现负权边时需要 Bellman-Ford,动手用并查集实现 Kruskal,最后通过在扩展状态图上运行 Dijkstra 的练习题来提升应用能力。
所有最短路径算法都建立在松弛操作之上,即检查经过 u 到达 v 是否更短;不同算法之间的区别只在于松弛边的顺序。
在权值非负时,用二叉堆每次取出并确定距离最近的顶点,可在 O((V + E) log V) 内求出单源最短距离。
Bellman-Ford 允许负权边并能检测负环;Floyd-Warshall 在 O(V^3) 内求出所有顶点对之间的距离。
Kruskal 按权值从小到大加边,并用并查集避免成环;Prim 从一棵树出发,每次加入最便宜的外连边。割性质保证了两者的正确性。
heapq 按距离从小到大取出 (距离, 顶点) 对;如果取出的距离大于已记录的值,说明是过期条目,直接跳过。当邻居的距离变短时,更新距离并把新的对压入堆中。运行 python dijkstra.py 会输出从 A 到各顶点的最短距离 {'A': 0, 'B': 3, 'C': 1, 'D': 4}。
dijkstra.py
import heapq
def dijkstra(graph, source):
dist = {source: 0}
heap = [(0, source)]
while heap:
d, u = heapq.heappop(heap)
if d > dist[u]:
continue # stale entry
for v, w in graph[u]:
nd = d + w
if nd < dist.get(v, float("inf")):
dist[v] = nd
heapq.heappush(heap, (nd, v))
return dist
graph = {
"A": [("B", 4), ("C", 1)],
"B": [("D", 1)],
"C": [("B", 2), ("D", 5)],
"D": [],
}
print(dijkstra(graph, "A")) # {'A': 0, 'B': 3, 'C': 1, 'D': 4}
python dijkstra.py共六章,带你从安装一步步了解 最短路径与最小生成树 的核心概念。
在这里提问、分享经验,交流关于 最短路径与最小生成树 的看法。
还没有讨论。来发起第一个吧。
0 条评论
登录 · 登录后即可发表评论。
来发表第一条评论吧。