Floyd-Warshall アルゴリズム は重み付き有向グラフのすべての頂点対に対して最短路距離を求める代表的なアルゴリズムです.グラフの頂点を とし, 配列 の 成分をグラフの 間の枝長 (枝がなければ , はゼロ) で初期化してから以下の3重ループを実行すると,すべての頂点 , についてそれらの間の最短路長が に入ります(ただしグラフは負閉路をもたないとします).
# Floyd-Warshall アルゴリズム
for k = 1, ..., n:
for i = 1, ..., n:
for j = 1, ..., n:
d[i,j] = min(d[i,j], d[i,k] + d[k,j])
ところで,Floyd--Warshall アルゴリズムのよくある実装ミスに「ループの添字の順序を間違える」ことがあります 1 .正しい順序 KIJ に対して,順序を間違えた実装をそれぞれ「IJK アルゴリズム」,「IKJ アルゴリズム」と呼ぶことにします.
# IJK アルゴリズム
for i = 1, ..., n:
for j = 1, ..., n:
for k = 1, ..., n:
d[i,j] = min(d[i,j], d[i,k] + d[k,j])
# IKJ アルゴリズム
for i = 1, ..., n:
for k = 1, ..., n:
for j = 1, ..., n:
d[i,j] = min(d[i,j], d[i,k] + d[k,j])
これらはもちろん正しい結果を出さないのですが,実は以下のことが証明できます.
定理 1. IJK アルゴリズムを3回実行すると に正しい値が代入される.
定理 2. IKJ アルゴリズムを2回実行すると に正しい値が代入される.
間違ったアルゴリズムを3回実行しても計算量は正しい Floyd-Warshall アルゴリズムとたかだか定数倍しか変わらないので,これらの結果から「Floyd-Warshall のループの添字順序がわからなくなったら,念のため3回実行すれば OK」ということがわかります.
証明のアイデア
3回・2回で十分であることを示すのは少し大変なので,ここでは基本的なアイデアをつかむために 回繰り返せば全点対間最短路長が正しく求まることを示します.
Floyd-Warshall アルゴリズムの更新 d[i,j] <- min(d[i,j], d[i,k] + d[k,j]) は,グラフの頂点対 に新しい枝を張る(長さは を中継したときの距離)操作に対応します.ここで重要となるのは この更新によってグラフの最短路長は変化しない(ただし最短路そのものは変化しうる) という性質です.定理の証明では,適当な回数アルゴリズムを繰り返すことでグラフが長さ1の最短路をもつようになることを示します.
定理 3. IJK アルゴリズムもしくは IKJ アルゴリズムを 回実行すると に正しい値が代入される.
証明.
適当に頂点 を固定し,それらの間の最短路 をとる ().すると,IJK アルゴリズムもしくは IKJ アルゴリズムを実行することでグラフに新たに枝 が追加されるので,アルゴリズム実行後のグラフは長さが元の半分の 間最短路 をもつ.したがってアルゴリズムを 回繰り返すとグラフは長さ の最短路をもつようになる.これは が全点対間最短路長であることを意味する.//
反復回数が3回・2回で十分なことを示すには,アルゴリズム実行後に「特殊な添字構造をもつ最短路」がとれることを示すことになります.詳しくは https://arxiv.org/abs/1904.01210 を参照してください.