リリース・改善中
Algorithm
ダイクストラ法・ベルマン–フォード法・ワーシャル–フロイド法で最短経路を求め、クラスカル法とプリム法で最小全域木を作る方法をまとめます。
最短経路問題は、重み付きグラフで頂点から頂点へ向かう経路のうち、重みの合計が最小のものを求める問題です。最小全域木(MST)は、無向グラフのすべての頂点を閉路なしでつなぐ辺の集合のうち、重みの合計が最小のものです。この分野の中心となるアルゴリズムは、ダイクストラ法、ベルマン–フォード法、ワーシャル–フロイド法、0-1 BFS、クラスカル法、プリム法です。
これらのアルゴリズムは、地図アプリの経路探索、OSPF や RIP などのルーティングプロトコル、ゲームの経路探索、ケーブルや配管の設計、クラスタリングといった実際のシステムで使われています。コーディング面接や競技プログラミングでも定番です。問題をグラフとしてモデル化し、重みの性質(負の値があるか、0 と 1 だけか、疎か密か)に合ったアルゴリズムを選べるかが問われるからです。
まず BFS と優先度付きキュー(ヒープ)に慣れておきましょう。次に、すべての最短経路アルゴリズムに共通する緩和(relaxation)を理解し、小さなグラフでダイクストラ法を手でたどります。続いて負の辺があるとベルマン–フォード法が必要になる理由を確かめ、Union-Find を使うクラスカル法を実装し、最後に状態を拡張したグラフでダイクストラ法を動かす練習問題に取り組みます。
すべての最短経路アルゴリズムは「u を経由すると v までが短くなるか」を確かめて距離を更新する緩和操作の上に成り立っており、違いは辺を緩和する順序だけです。
重みが非負なら、二分ヒープで最も近い頂点を取り出して確定させ、一つの始点からの最短距離を O((V + E) log V) ですべて求めます。
ベルマン–フォード法は負の辺を扱え、負閉路を検出できます。ワーシャル–フロイド法はすべての頂点対の距離を O(V^3) で求めます。
クラスカル法は軽い辺から順に加え、Union-Find で閉路を防ぎます。プリム法は一本の木を最も安い外向きの辺で育てます。どちらもカット性によって正しさが保証されます。
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インストールから 最短経路と最小全域木 の中心となる考え方まで、6 章で順を追って学びます。
最短経路と最小全域木 について質問し、経験を共有し、意見を交わす場所です。
まだディスカッションはありません。最初の話題を始めましょう。
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。