已發布·持續改進
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 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。