Slide 1

Slide 1 text

グラフアルゴリズムその2 単一始点最短路問題 2018-01-30 宮川 拓

Slide 2

Slide 2 text

参考  『アルゴリズムイントロダクション』, 第3版, 24章「単一始点最短路問題」 2/42

Slide 3

Slide 3 text

def 最短路問題  グラフの頂点間をつなぐ最短の道と、その 重みを求める 3/42

Slide 4

Slide 4 text

最短路問題の分類  単一始点最短路問題:  始点sから各頂点への最短路を求める  単一目的地最短路問題:  各頂点から目的地tへの最短路を求める  本質的には単一始点最短路問題と同じ  単一点対最短路問題:  ある頂点対(u, v)間の最短路を求める  uを始点とする単一始点最短路問題の部分問題  全点対最短路問題:  すべての頂点対(u, v)間の最短路を求める 4/42

Slide 5

Slide 5 text

最短路問題の分類  重み付きグラフ  重みなしグラフ  → 幅優先探索で解ける 5/42

Slide 6

Slide 6 text

最短路問題の分類  負の重みを持つ辺が含まれない場合  負の重みを持つ辺が含まれる場合  負の重みを持つ閉路がある場合、最短路 が定義できない頂点対が出現する t v s u -5 -3 2 4 (u, t, v)より(u, t, v, s, t, v), (u, t, v, s, t, v, s, t, v),,, の方が短い 6/42

Slide 7

Slide 7 text

取り上げるアルゴリズム  Bellman-Fordアルゴリズム  負の重みを持つ辺が扱える  負閉路が検出できる  遅い  Dijkstraのアルゴリズム  負の重みを持つ辺が扱えない  速い 7/42

Slide 8

Slide 8 text

Bellman-Fordアルゴリズム 8/42

Slide 9

Slide 9 text

データ構造 頂点 = { Pred: (暫定)最短路で1つ手前の頂点 Dist: (暫定)最短路で始点からの距離 } // 探索が終わった時点で、暫定でなくなる 辺 = { From: 矢羽側の頂点 To: 矢尻側の頂点 Weight: 辺重み } 9/42

Slide 10

Slide 10 text

Bellman-Fordアルゴリズム 始点のDistを0に、始点以外のDistを∞に設定 loop (頂点の数 - 1) 回: // ← なんで? for すべての辺(From To Weight): D = From.Dist + Weight if D が To.Distよりも短ければ: Toを更新: .Pred=From .Dist=D endif endfor endloop この時点でFrom.Dist+Weight < To.Dist となる辺があれば、グラフは負閉路を含んでいる 10/42

Slide 11

Slide 11 text

例題 c d e b a S 1 2 1 4 6 1 2 3 11/42

Slide 12

Slide 12 text

探索開始 ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 12/42

Slide 13

Slide 13 text

ループ1: d→a ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 変更なし ※From側のDistが∞だから 13/42

Slide 14

Slide 14 text

ループ1: c→b ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 変更なし 14/42

Slide 15

Slide 15 text

ループ1: c→d ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 変更なし 15/42

Slide 16

Slide 16 text

ループ1: b→d ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 変更なし 16/42

Slide 17

Slide 17 text

ループ1: a→c ∞ ∞ ∞ ∞ ∞ 0 1 2 1 4 6 1 2 3 変更なし 17/42

Slide 18

Slide 18 text

ループ1: S→a ∞ ∞ ∞ ∞ 1 0 1 2 1 4 6 1 2 3 変更: ∞→1 18/42

Slide 19

Slide 19 text

ループ1: S→b ∞ ∞ ∞ 1 1 0 1 2 1 4 6 1 2 3 変更: ∞→1 19/42

Slide 20

Slide 20 text

ループ1: S→c 6 ∞ ∞ 1 1 0 1 2 1 4 6 1 2 3 変更: ∞→6 20/42

Slide 21

Slide 21 text

ループ2: d→a 6 ∞ ∞ 1 1 0 1 2 1 4 6 1 2 3 変更なし 21/42

Slide 22

Slide 22 text

ループ2: c→b 6 ∞ ∞ 1 1 0 1 2 1 4 6 1 2 3 変更なし 22/42

Slide 23

Slide 23 text

ループ2: c→d 6 7 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更: ∞→7 23/42

Slide 24

Slide 24 text

ループ2: b→d 6 5 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更: 7→5 24/42

Slide 25

Slide 25 text

ループ2: a→c 3 5 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更: 6→3 25/42

Slide 26

Slide 26 text

ループ2: S→a 3 5 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更なし 26/42

Slide 27

Slide 27 text

ループ2: S→b 3 5 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更なし 27/42

Slide 28

Slide 28 text

ループ2: S→c 3 5 ∞ 1 1 0 1 2 1 4 6 1 2 3 変更なし 28/42

Slide 29

Slide 29 text

ループ5終了時点 3 4 ∞ 1 1 0 1 2 1 4 6 1 2 3 観察:  各頂点に、0/1個のpredが設定されている  最短路の部分経路もまた最短路である 29/42

Slide 30

Slide 30 text

Bellman-Fordアルゴリズム 始点のDistを0に、始点以外のDistを∞に設定 loop (頂点の数 - 1) 回: // ← なんで? for すべての辺(From To Weight): D = From.Dist + Weight if D が To.Distよりも短ければ: Toを更新: .Pred=From .Dist=D endif endfor endloop この時点でFrom.Dist+Weight < To.Dist となる辺があれば、グラフは負閉路を含んでいる 30/42

Slide 31

Slide 31 text

繰り返し回数の直感的理解  頂点の数だけが与えられている場合、 最短路の辺の数は高々(頂点数-1) 例: 6頂点(S, a, b, c, d, e)→5辺  (頂点数-1)回だけ繰り返せば、すべての 最短路のすべての辺がたどられるはず 31/42

Slide 32

Slide 32 text

Bellman-Fordアルゴリズム 始点のDistを0に、始点以外のDistを∞に設定 loop (頂点の数 - 1) 回: for すべての辺(From To Weight): D = From.Dist + Weight if D が To.Distよりも短ければ: Toを更新: .Pred=From .Dist=D endif endfor endloop この時点でFrom.Dist+Weight < To.Dist となる辺があれば、グラフは負閉路を含んでいる 計算量: O(頂点数*辺数) 32/42

Slide 33

Slide 33 text

Dijkstraのアルゴリズム 33/42

Slide 34

Slide 34 text

データ構造 頂点 = { Pred: (暫定)最短路で1つ手前の頂点 Dist: (暫定)最短路で始点からの距離 Neibors: (矢印の先の頂点, 重み)の集合 } 頂点の優先度付きキュー = { extractMin(): 距離が最も小さい頂点を抜き出す decreaseKey(V, Dist): 頂点Vの距離を更新する } // 距離を優先度とする 34/42

Slide 35

Slide 35 text

Dijkstraのアルゴリズム 始点のDistを0に、始点以外のDistを∞に設定 Q = すべての頂点を含む優先度付きキュー while Qが空でない間: Min = Q.extractMin() for すべてのMin.neibors → (V, Weight) : D = Min.dist + Weight if DがV.distよりも短ければ: Vを更新: .Pred=Min .Dist=D Q.decreaseKey(V, D) endif endfor endwhile 35/42

Slide 36

Slide 36 text

直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Sの 中 の 頂 点 は 最短路が確定している 最短路は Sに含まれる 頂点だけで構成される 36/42

Slide 37

Slide 37 text

直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Qの 中 の 頂 点 は 最短路が未確定 Sの中の頂点から来る 道があれば、 そのいずれかが 暫定最短路として 設定されている 37/42

Slide 38

Slide 38 text

直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Min Qか ら 、 暫定距離が最も短い 頂点Minを選ぶ 38/42

Slide 39

Slide 39 text

直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Min Minの最短路は 確定できる! Qの 中 の 他 の 頂 点 を たどる道が 最短路であることは ないから ※ 負辺はない前提 39/42

Slide 40

Slide 40 text

直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Min MinからQへの 暫定最短路があれば 更新する 40/42

Slide 41

Slide 41 text

Dijkstraのアルゴリズムの計算量 始点のDistを0に、始点以外のDistを∞に設定 Q = すべての頂点を含む優先度付きキュー while Qが空でない間: Min = Q.extractMin() for すべてのMin.neibors → (V, Weight) : D = Min.dist + Weight if DがV.distよりも短ければ: Vを更新: .Pred=Min .Dist=D Q.decreaseKey(V, D) endif endfor endwhile 頂 点 数 回 実 行 さ れ る だ い た い 辺 数 回 実 行 さ れ る 41/42

Slide 42

Slide 42 text

Dijkstraのアルゴリズムの計算量 優先度付きキューの操作の計算量に依存 優先度付き キューの実装 extractMin decrease Key Dijkstraの計算量 2 分ヒープ Θ(log N) Θ(log N ) Θ(辺数* log頂点数 +頂点数* log頂 点 数) フィボナッチ ヒープ Θ(log N) Θ(1) ※ならし Θ(辺数 +頂点数* log頂 点 数) ※ならし 計算量は漸近的にフィボナッチヒープが有利 フィボナッチヒープの実装は複雑、 2分ヒープは単純なので、 グラフが小さい場合は 2分ヒープを使う方が有利 42/42 ※N = 優先度付きキューの要素数