Upgrade to Pro — share decks privately, control downloads, hide ads and more …

グラフアルゴリズムその2: 単一始点最短路問題 /graphShortestPaths

グラフアルゴリズムその2: 単一始点最短路問題 /graphShortestPaths

5e8c7a93f4cd63b62ced5dd347f1a8e0?s=128

Miyakawa Taku

January 29, 2018
Tweet

Transcript

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

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

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

  4. 最短路問題の分類  単一始点最短路問題:  始点sから各頂点への最短路を求める  単一目的地最短路問題:  各頂点から目的地tへの最短路を求める 

    本質的には単一始点最短路問題と同じ  単一点対最短路問題:  ある頂点対(u, v)間の最短路を求める  uを始点とする単一始点最短路問題の部分問題  全点対最短路問題:  すべての頂点対(u, v)間の最短路を求める 4/42
  5. 最短路問題の分類  重み付きグラフ  重みなしグラフ  → 幅優先探索で解ける 5/42

  6. 最短路問題の分類  負の重みを持つ辺が含まれない場合  負の重みを持つ辺が含まれる場合  負の重みを持つ閉路がある場合、最短路 が定義できない頂点対が出現する 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
  7. 取り上げるアルゴリズム  Bellman-Fordアルゴリズム  負の重みを持つ辺が扱える  負閉路が検出できる  遅い 

    Dijkstraのアルゴリズム  負の重みを持つ辺が扱えない  速い 7/42
  8. Bellman-Fordアルゴリズム 8/42

  9. データ構造 頂点 = { Pred: (暫定)最短路で1つ手前の頂点 Dist: (暫定)最短路で始点からの距離 } //

    探索が終わった時点で、暫定でなくなる 辺 = { From: 矢羽側の頂点 To: 矢尻側の頂点 Weight: 辺重み } 9/42
  10. 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
  11. 例題 c d e b a S 1 2 1

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

    4 6 1 2 3 12/42
  13. ループ1: d→a ∞ ∞ ∞ ∞ ∞ 0 1 2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    1 4 6 1 2 3 変更なし 28/42
  29. ループ5終了時点 3 4 ∞ 1 1 0 1 2 1

    4 6 1 2 3 観察:  各頂点に、0/1個のpredが設定されている  最短路の部分経路もまた最短路である 29/42
  30. 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
  31. 繰り返し回数の直感的理解  頂点の数だけが与えられている場合、 最短路の辺の数は高々(頂点数-1) 例: 6頂点(S, a, b, c, d,

    e)→5辺  (頂点数-1)回だけ繰り返せば、すべての 最短路のすべての辺がたどられるはず 31/42
  32. 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
  33. Dijkstraのアルゴリズム 33/42

  34. データ構造 頂点 = { Pred: (暫定)最短路で1つ手前の頂点 Dist: (暫定)最短路で始点からの距離 Neibors: (矢印の先の頂点,

    重み)の集合 } 頂点の優先度付きキュー = { extractMin(): 距離が最も小さい頂点を抜き出す decreaseKey(V, Dist): 頂点Vの距離を更新する } // 距離を優先度とする 34/42
  35. 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
  36. 直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Sの 中 の 頂 点 は 最短路が確定している

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

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

  39. 直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Min Minの最短路は 確定できる! Qの 中 の 他

    の 頂 点 を たどる道が 最短路であることは ないから ※ 負辺はない前提 39/42
  40. 直感的な理解 最短路と距離が確定した頂点の集合S 最短路と距離が未確定の頂点の集合Q Min MinからQへの 暫定最短路があれば 更新する 40/42

  41. 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
  42. Dijkstraのアルゴリズムの計算量 優先度付きキューの操作の計算量に依存 優先度付き キューの実装 extractMin decrease Key Dijkstraの計算量 2 分ヒープ

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