回 2-8 道 2 データ構造とアルゴリズム
ダイクストラ法は、
読み終えたら乗り換え案内のような
この頁の流れ
乗り換え案内のような
本町から 空港まで、 一番早い 行き方を どう求めるか
一番早い
本町から
駅が
この
ダイクストラ法は どう 最短経路を 求めるのか
ダイクストラ法は、
点と 線と 重みで、 駅と 線路を表す
グラフは、
この
| 駅 | 駅 | 分 |
|---|---|---|
| 本町 | 港 | 5 |
| 本町 | 丘 | 2 |
| 丘 | 港 | 2 |
| 港 | 空港 | 10 |
| 丘 | 川 | 6 |
| 川 | 空港 | 3 |
| 本町 | 空港 | 18 |
プログラムでは、
一番近い点を 確定し、 隣を書き直す
手順は
- 出発点の
距離を 0、 ほかの 点の 距離を 無限大 (まだ 行き方を 知らない 印) にする - まだ
確定していない 点の うち、 距離が 一番小さい 点を 選び、確定する - 確定した
点の 隣に ついて、 「確定した 点の 距離 + 線の 重み」が 今の 距離より 小さければ、 距離を 書き直し、 どこから 来たか (前の 点) を覚える - すべての
点が 確定するまで 2 と 3 を繰り返す
確定とは
一番近い点を、 ヒープで 速く取り出す
手順のheapq で
heapq のheap[0] にあり、heappop は(距離, 点) の
公式文書は、
幅優先探索と どう違うのか
幅優先探索 (BFS) は、
| 探し方 | 線の重み | 出す答え | 使う入れ物 |
|---|---|---|---|
| 幅優先探索 | 全部同じ | 線の | キュー (deque) |
| ダイクストラ法 | 0 以上 | 重みの | 優先度付きキュー (heapq) |
| ベルマン・フォード法 | 負もよい | 重みの | 線の |
| 深さ優先探索 | 見ない | 行けるか | スタック |
深さ優先探索は
動かして確かめる
1 本目は、inf は math.inf で、
動かす 乗り換え案内をダイクストラ法で解く
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
確定 本町 0
更新 港 inf → 5
更新 丘 inf → 2
更新 空港 inf → 18
確定 丘 2
更新 港 5 → 4
更新 川 inf → 8
確定 港 4
更新 空港 18 → 14
捨てる 港 5
確定 川 8
更新 空港 14 → 11
確定 空港 11
捨てる 空港 14
捨てる 空港 18
本町→丘→川→空港
札 8 線 14最初に
空港は
経路は、
入れた
2 本目は、
動かす 幅優先探索とダイクストラ法を比べる
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
駅 線の本数 分
本町 0 0
港 1 4
丘 1 2
空港 1 11
川 2 8
全部 1 で同じ True幅優先探索では
重みを
ダイクストラ法は どこで 崩れるのか
ダイクストラ法は、
負の 重みの 線が あると、 確定が早すぎる
次の
動かす 負の重みの線で答えを誤る
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
点 求めた 正しい
A 2 1
B 5 5
C 3 2
縮んだ数 1
点 求めた 正しい
A 2 2
B 5 5
C 3 3
縮んだ数 0負の
順に
負の
なぜ 確定した 点を 後から 直さなくてよいのか
重みが
ある
負の
ダイクストラ法は 仕事で どう 確かめるのか
仕事では、
- 図を
作る ときに、 線の 重みが 全部 0 以上かを 確かめる。 負の 数が 混ざるなら、 ダイクストラ法を使わない - 重みが
全部同じなら、 幅優先探索で 足りる。 ヒープを 使うのは 重みが 違う ときだけにする - 試験では、
小さな 図で、上の bruteのように全部 たどった 答えと 一致するかを見る - 出した
経路の 線の 重みを 足し直し、 求めた 距離と 同じかを見る - 行けない
点の 距離は 無限大のまま 残るので、 その 場合の 表示を 決めておく
ダイクストラ法の試験
def test_weights_not_negative():
for a, b, m in lines:
assert m >= 0, (a, b)
def test_route_sum():
total = 0
for x, y in zip(p, p[1:]):
total += dict(adj[x])[y]
assert total == dist["空港"]関わる実例
1956年、 64 の 都市の 地図で 最短の 道を見せた
Communications of the ACM の
発表は
出典は An Interview with Edsger W. Dijkstra (Communications of the ACM) と A note on two problems in connexion with graphs (Numerische Mathematik) です。
OSPF は、 線の 重みを 0 より 大きく 決めている (1998年4月)
1998年4月の
同じ
よくある問い
ダイクストラ法の 計算量は どの くらいですか
点のheapq の
幅優先探索 (BFS) と ダイクストラ法は どう 使い 分けますか
線の
最短経路の 簡単な 解き方は ありますか
点がbrute のように
すべての 駅の 組の 最短を 出すには どうしますか
重みが
確認クイズ
答えだと
1 問目
所要の
2 問目
この
小さな図のダイクストラ法
from heapq import heappop
from heapq import heappush
adj = {
"A": [("B", 4), ("C", 1)],
"B": [],
"C": [("B", 2)],
}
dist = {"A": 0}
h = [(0, "A")]
while h:
d, u = heappop(h)
for v, w in adj[u]:
nd = d + w
if nd < dist.get(v, 99):
dist[v] = nd
heappush(h, (nd, v))
print(dist["B"])3 問目
ダイクストラ法で、
4 問目
線 S→A が
説明課題
乗り換え案内で
自分の
この回の 先の一歩
経路の
もっと深く
この
一次資料
どれも
- A note on two problems in connexion with graphs (Numerische Mathematik、英語)。第 1 巻 269〜271 ページ、
1959年12月の 号に出たこと - An Interview with Edsger W. Dijkstra (Communications of the ACM、
2010年8月号、英語)。1956年の ARMAC の お披露目、 64 の 都市と 6 ビット、 約 20 分で 考えた こと、 当時は 数学と 見な されなかった こと、 今は 道案内に 使われていること - RFC 2328 OSPF Version 2 (RFC Editor、
英語、 1998年4月)。向きの ある グラフとして 持ち、 最短経路の 木を ダイクストラ法で 作る こと (16.1 節)、 つなぎ口の 重みを 0 より 大きくすること - heapq, Heap queue algorithm (Python 公式文書、英語)。一番小さい物が
heap[0]にあること、 heappop、組を入れて優先度を 付ける こと、 優先度を 変えずに 入れ直す方 法、 取り出しの 手間が log に 比例すること - math, Mathematical functions (Python 公式文書、英語)。
math.infが正の 無限大であること
次へ
道 2 データ構造とアルゴリズムの回
- 2-0アルゴリズムとは順次、
分岐、 反復の 3 つで書く手順頁で読む - 2-1線形探索と二分探索100 万件でも
20 回で見つかる頁で読む - 2-2バブルソートと
挿入・選択ソート遅い ソート 3 つ、 2 倍で 約 4 倍頁で読む - 2-3クイックソートと
マージソート速い ソート 2 つ、 平均と最悪頁で読む - 2-4スタックとキュー積む順と並ぶ順頁で読む
- 2-5再帰自分を
呼んで 小さくする頁で読む - 2-6木と
二分探索木たどる 順、片寄り頁で読む - 2-7ハッシュテーブル鍵から
一気に 引く、衝突頁で読む - 2-8ダイクストラ法と最短経路点と
線、 幅優先、 重みのある道この回 - 2-9動的計画法同じ
計算を 2 度しない頁で読む - 2-10試験と
面接で確かめる基本情報 科目B、 道場 10 問、 面接 20 問頁で読む
