グラフアルゴリズムその2単一始点最短路問題2018-01-30宮川 拓
View Slide
参考 『アルゴリズムイントロダクション』,第3版, 24章「単一始点最短路問題」2/42
def 最短路問題 グラフの頂点間をつなぐ最短の道と、その重みを求める3/42
最短路問題の分類 単一始点最短路問題: 始点sから各頂点への最短路を求める 単一目的地最短路問題: 各頂点から目的地tへの最短路を求める 本質的には単一始点最短路問題と同じ 単一点対最短路問題: ある頂点対(u, v)間の最短路を求める uを始点とする単一始点最短路問題の部分問題 全点対最短路問題: すべての頂点対(u, v)間の最短路を求める4/42
最短路問題の分類 重み付きグラフ 重みなしグラフ → 幅優先探索で解ける5/42
最短路問題の分類 負の重みを持つ辺が含まれない場合 負の重みを持つ辺が含まれる場合 負の重みを持つ閉路がある場合、最短路が定義できない頂点対が出現するtvsu-5-32 4(u, t, v)より(u, t, v, s, t, v),(u, t, v, s, t, v, s, t, v),,, の方が短い6/42
取り上げるアルゴリズム Bellman-Fordアルゴリズム 負の重みを持つ辺が扱える 負閉路が検出できる 遅い Dijkstraのアルゴリズム 負の重みを持つ辺が扱えない 速い7/42
Bellman-Fordアルゴリズム8/42
データ構造頂点 = {Pred: (暫定)最短路で1つ手前の頂点Dist: (暫定)最短路で始点からの距離}// 探索が終わった時点で、暫定でなくなる辺 = {From: 矢羽側の頂点To: 矢尻側の頂点Weight: 辺重み}9/42
Bellman-Fordアルゴリズム始点のDistを0に、始点以外のDistを∞に設定loop (頂点の数 - 1) 回: // ← なんで?for すべての辺(From To Weight):D = From.Dist + Weightif D が To.Distよりも短ければ:Toを更新: .Pred=From .Dist=Dendifendforendloopこの時点でFrom.Dist+Weight < To.Distとなる辺があれば、グラフは負閉路を含んでいる10/42
例題cd ebaS1214612311/42
探索開始∞∞ ∞∞∞01214612312/42
ループ1: d→a∞∞ ∞∞∞012146123変更なし※From側のDistが∞だから13/42
ループ1: c→b∞∞ ∞∞∞012146123変更なし14/42
ループ1: c→d∞∞ ∞∞∞012146123変更なし15/42
ループ1: b→d∞∞ ∞∞∞012146123変更なし16/42
ループ1: a→c∞∞ ∞∞∞012146123変更なし17/42
ループ1: S→a∞∞ ∞∞1012146123変更: ∞→118/42
ループ1: S→b∞∞ ∞11012146123変更: ∞→119/42
ループ1: S→c6∞ ∞11012146123変更: ∞→620/42
ループ2: d→a6∞ ∞11012146123変更なし21/42
ループ2: c→b6∞ ∞11012146123変更なし22/42
ループ2: c→d67 ∞11012146123変更: ∞→723/42
ループ2: b→d65 ∞11012146123変更: 7→524/42
ループ2: a→c35 ∞11012146123変更: 6→325/42
ループ2: S→a35 ∞11012146123変更なし26/42
ループ2: S→b35 ∞11012146123変更なし27/42
ループ2: S→c35 ∞11012146123変更なし28/42
ループ5終了時点34 ∞11012146123観察: 各頂点に、0/1個のpredが設定されている 最短路の部分経路もまた最短路である29/42
Bellman-Fordアルゴリズム始点のDistを0に、始点以外のDistを∞に設定loop (頂点の数 - 1) 回: // ← なんで?for すべての辺(From To Weight):D = From.Dist + Weightif D が To.Distよりも短ければ:Toを更新: .Pred=From .Dist=Dendifendforendloopこの時点でFrom.Dist+Weight < To.Distとなる辺があれば、グラフは負閉路を含んでいる30/42
繰り返し回数の直感的理解 頂点の数だけが与えられている場合、最短路の辺の数は高々(頂点数-1)例: 6頂点(S, a, b, c, d, e)→5辺 (頂点数-1)回だけ繰り返せば、すべての最短路のすべての辺がたどられるはず31/42
Bellman-Fordアルゴリズム始点のDistを0に、始点以外のDistを∞に設定loop (頂点の数 - 1) 回:for すべての辺(From To Weight):D = From.Dist + Weightif D が To.Distよりも短ければ:Toを更新: .Pred=From .Dist=Dendifendforendloopこの時点でFrom.Dist+Weight < To.Distとなる辺があれば、グラフは負閉路を含んでいる計算量:O(頂点数*辺数)32/42
Dijkstraのアルゴリズム33/42
データ構造頂点 = {Pred: (暫定)最短路で1つ手前の頂点Dist: (暫定)最短路で始点からの距離Neibors: (矢印の先の頂点, 重み)の集合}頂点の優先度付きキュー = {extractMin(): 距離が最も小さい頂点を抜き出すdecreaseKey(V, Dist): 頂点Vの距離を更新する}// 距離を優先度とする34/42
Dijkstraのアルゴリズム始点のDistを0に、始点以外のDistを∞に設定Q = すべての頂点を含む優先度付きキューwhile Qが空でない間:Min = Q.extractMin()for すべてのMin.neibors → (V, Weight) :D = Min.dist + Weightif DがV.distよりも短ければ:Vを更新: .Pred=Min .Dist=DQ.decreaseKey(V, D)endifendforendwhile35/42
直感的な理解最短路と距離が確定した頂点の集合S最短路と距離が未確定の頂点の集合QSの 中 の 頂 点 は最短路が確定している最短路は Sに含まれる頂点だけで構成される36/42
直感的な理解最短路と距離が確定した頂点の集合S最短路と距離が未確定の頂点の集合Q Qの 中 の 頂 点 は最短路が未確定Sの中の頂点から来る道があれば、そのいずれかが暫定最短路として設定されている37/42
直感的な理解最短路と距離が確定した頂点の集合S最短路と距離が未確定の頂点の集合QMinQか ら 、暫定距離が最も短い頂点Minを選ぶ38/42
直感的な理解最短路と距離が確定した頂点の集合S最短路と距離が未確定の頂点の集合QMinMinの最短路は確定できる!Qの 中 の 他 の 頂 点 をたどる道が最短路であることはないから※ 負辺はない前提39/42
直感的な理解最短路と距離が確定した頂点の集合S最短路と距離が未確定の頂点の集合QMinMinからQへの暫定最短路があれば更新する40/42
Dijkstraのアルゴリズムの計算量始点のDistを0に、始点以外のDistを∞に設定Q = すべての頂点を含む優先度付きキューwhile Qが空でない間:Min = Q.extractMin()for すべてのMin.neibors → (V, Weight) :D = Min.dist + Weightif DがV.distよりも短ければ:Vを更新: .Pred=Min .Dist=DQ.decreaseKey(V, D)endifendforendwhile頂 点 数 回実 行 さ れ るだ い た い 辺 数 回実 行 さ れ る41/42
Dijkstraのアルゴリズムの計算量優先度付きキューの操作の計算量に依存優先度付きキューの実装extractMindecreaseKeyDijkstraの計算量2 分ヒープ Θ(log N) Θ(log N )Θ(辺数* log頂点数+頂点数* log頂 点 数)フィボナッチヒープΘ(log N)Θ(1)※ならしΘ(辺数+頂点数* log頂 点 数)※ならし計算量は漸近的にフィボナッチヒープが有利フィボナッチヒープの実装は複雑、 2分ヒープは単純なので、グラフが小さい場合は 2分ヒープを使う方が有利42/42※N = 優先度付きキューの要素数