在前兩天我們分別介紹了 Dijkstra 與 Bellman-Ford ,它們都解決的是 單源最短路徑 (Single Source Shortest Path, SSSP) 問題。今天要介紹的是 Floyd-Warshall 演算法 —— 一個能計算 所有點對 (All-Pairs Shortest Path, APSP) 的演算法
Floyd-Warshall 採用 動態規劃 (Dynamic Programming, DP) 的方式,逐步引入節點作為「中繼點」,不斷更新最短路徑
定義狀態:
轉移方程:
$$
dist[i][j] = \min(dist[i][j], ; dist[i][k] + dist[k][j])
$$
意思是: 如果從 $i$ 經過 $k$ 再到 $j$ 的路徑更短,就更新 $dist[i][j]$
INF = float('inf')
def floyd_warshall(graph):
# graph: adjacency matrix 格式
V = len(graph)
dist = [row[:] for row in graph] # 複製矩陣
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist
# 測試
graph = [
[0, 3, INF, 7],
[8, 0, 2, INF],
[5, INF, 0, 1],
[2, INF, INF, 0]
]
result = floyd_warshall(graph)
for row in result:
print(row)
相較於 Dijkstra 與 Bellman-Ford,Floyd-Warshall 適合 節點數不多 (n ≤ 400~500) 的情境,因為它會遍歷所有三元組 $(i, j, k)$
優點 | 缺點 |
---|---|
能處理所有點對最短路徑 | 複雜度高 ($O(V^3)$),不適合大圖 |
支援負權重 | 不能處理負權重環 |
程式結構簡單,實作方便 | 記憶體需求 $O(V^2)$,稠密圖時開銷大 |
Floyd-Warshall 演算法雖然比不上 Dijkstra 與 Bellman-Ford 的效率,但它在小規模圖的全點對最短路徑問題中極具威力,它的動態規劃思想也為理解更複雜的演算法奠定基礎。