コンピュータサイエンスにおいて、フロイド・ウォーシャルアルゴリズム(フロイドのアルゴリズム、ロイ・ウォーシャルアルゴリズム、ロイ・フロイドアルゴリズム、またはWFIアルゴリズムとも呼ばれる)は、正または負のエッジ重みを持つ有向重み付きグラフ(ただし負のサイクルは含まない)の最短経路を見つけるためのアルゴリズムである。 [ 1 ] [ 2 ]このアルゴリズムを1回実行すると、すべての頂点ペア間の最短経路の長さ(重みの合計)が見つかる。経路自体の詳細は返されないが、アルゴリズムを少し変更することで経路を再構築することは可能である。このアルゴリズムのバージョンは、関係の推移閉包を見つけるためにも、または(シュルツェ投票システムに関連して)重み付きグラフのすべての頂点ペア間の最も広い経路を見つけるためにも使用できる。
フロイド・ウォーシャルアルゴリズムは動的計画法の例であり、現在知られている形では1962 年にロバート・フロイドによって発表されました。[ 3 ] しかし、これは基本的に、1959 年にバーナード・ロイによって発表されたアルゴリズム[4] や、1962 年にスティーブン・ウォーシャルによって発表されたグラフの推移閉包を見つけるアルゴリズム [5]と本質的に同じであり、決定性有限オートマトンを正規表現に変換するクリーネのアルゴリズム (1956 年に発表) と密接に関連しており、違いはmin - plus半環の使用です。[ 7 ] 3 つの入れ子になった for ループとしてのアルゴリズムの現代的な定式化は、同じく 1962 年にピーター・インガーマンによって初めて記述されました。[ 8 ]
フロイド・ウォーシャルアルゴリズムは、グラフ内の各頂点ペア間の多くの可能なパスを比較します。すべての最短パスを見つけることが保証されており、グラフでの比較、[ 1 ] [ 9 ]たとえグラフ内のエッジに対して、2つの頂点間の最短経路の推定値を段階的に改善し、推定値が最適になるまで繰り返します。
グラフを考えてみよう頂点を持つ1から さらに関数について考えてみましょう。最短経路の長さ(存在する場合)を返します。に頂点はセットからのみ使用する途中の地点として。さて、この関数が与えられたとき、私たちの目標は、各地点からの最短経路の長さを求めることです。それぞれに任意の頂点を使用して定義上、これは値ですこれは再帰的に見つけることになります。
注目してください以下でなければならない頂点の使用が許可されれば、より柔軟に対応できます。。 もし実際にはより少ないそうすれば、に頂点を使用してそれは、頂点を使用しないそのようなパスよりも短い。負のサイクルが存在しないため、このパスは次のように分解できます。
そしてもちろん、これらは最短経路(あるいは複数の最短経路)でなければなりません。そうでなければ、さらに長さを短くできてしまうからです。言い換えれば、次の漸化式にたどり着きました。
基本ケースは次のように与えられる。
どこは、エッジの重みを表します。に存在する場合は 、存在しない場合は ∞ (無限大) となります。
これらの数式はフロイド・ウォーシャルアルゴリズムの中核を成すものです。このアルゴリズムは、まず を計算することによって機能します。すべての人々のためにペア、 それから、 それからなど。このプロセスは、そして、私たちはすべての最短経路を見つけました任意の中間頂点を用いたペアリング。この基本バージョンの擬似コードを以下に示します。
dist を |V| × |V| の最小距離の配列とし、初期値を ∞ (無限大) と する。各エッジ ( u , v )について、dist [ u ][ v ] = w( u , v ) // エッジ ( u , v )の重みとする。各頂点vについて、 dist[ v ][ v ] = 0 とする。kを1から|V| まで、 iを1から|V| まで、 jを1から|V| までとする。dist [ i ][ j ] > dist[ i ][ k ] + dist[ k ][ j ]の場合、 dist[ i ][ j ] = dist[ i ][ k ] + dist[ k ][ j ] end if
注: フロイド-ウォーシャルアルゴリズムを実装する際のよくある間違いは、三重にネストされたループの順序を間違えることです (正しい順序は ですKIJ)。 と の間違ったIJKアルゴリズムIKJでは、インスタンスによっては正しい解が得られません。しかし、これらを 3 回繰り返すと、正しい解が得られることを証明できます。[ 10 ]
上記のアルゴリズムは、左下のグラフ上で実行されます。
![]()
上記でk = 0とラベル付けされた外側ループの最初の再帰の前には、既知のパスはグラフの単一のエッジのみに対応します。k = 1では、頂点 1 を通るパスが見つかります。特に、パス [2,1,3] が見つかり、エッジ数は少ないが (重みの点で) 長いパス [2,3] が置き換えられます。k = 2では、頂点 {1,2} を通るパスが見つかります。赤と青のボックスは、パス [4,2,1,3] が、以前の反復で遭遇した 2 つの既知のパス [4,2] と [2,1,3] からどのように組み立てられるかを示しており、交差部分に 2 が含まれています。パス [4,2,3] は考慮されません。これは、2 から 3 までの最短パスが [2,1,3] であるためです。k = 3では、頂点 {1,2,3} を通るパスが見つかります。最後に、k = 4 の時点で、すべての最短経路が見つかります。
kの各反復における距離行列(更新された距離は太字で示す)は次のようになる。
負のサイクルとは、辺の合計が負の値になるサイクルのことです。どの頂点のペア間にも最短経路は存在しません。、これは負のサイクルの一部を形成します。なぜなら、経路の長さはには任意に小さい値(負の値)をとることができます。数値的に意味のある出力を得るために、フロイド・ウォーシャルアルゴリズムは負のサイクルが存在しないことを前提としています。しかし、負のサイクルが存在する場合でも、フロイド・ウォーシャルアルゴリズムを使用してそれらを検出できます。その直感的な説明は次のとおりです。
したがって、Floyd–Warshallアルゴリズムを使用して負のサイクルを検出するには、パス行列の対角線を調べればよく、負の数が存在する場合は、グラフに少なくとも1つの負のサイクルが含まれていることを示します。[ 9 ]ただし、負のサイクルが存在する場合、アルゴリズムの実行中に指数関数的に大きな数(オーダー)が発生します。現れる可能性があるはグラフ内の最大の絶対値のエッジ重みです。整数アンダーフローの問題を回避するには、アルゴリズムの最も内側の for ループ内で負のサイクルをチェックする必要があります。[ 11 ]
フロイド・ウォーシャルアルゴリズムは通常、すべての頂点ペア間のパスの長さのみを提供します。簡単な修正を加えることで、任意の2つの端点頂点間の実際のパスを再構築する方法を作成できます。各頂点から他のすべての頂点への実際のパスを保存したくなるかもしれませんが、これは必要なく、実際にはメモリの面で非常にコストがかかります。代わりに、最短パスツリーを使用できます。これは、各ノードについて計算できます。時間を使うメモリを使用することで、接続された任意の2つの頂点間の有向パスを効率的に再構築できます。
配列には、からへのprev[u][v]パス上の最後から2番目の頂点が格納されます(ただし、の場合、に自己ループがない場合でも常にが含まれます)。[ 12 ]uvprev[v][v]vv
distを最小距離の配列を初期化します(無限) prevをnullで初期化された頂点インデックスの配列プロシージャFloydWarshallWithPathReconstruction ()は、各エッジ (u, v)に対して 、dist[u][v] = w(u, v) // エッジ (u, v) の重みを実行します。 prev[u][v] = u 各頂点vについて dist[v][v] = 0 prev[v][v] = v kを1から|V|まで繰り返す// 標準的な Floyd-Warshall 実装 i を1から|V| まで繰り返すj を1から|V| まで繰り返すもしdist[i][j] > dist[i][k] + dist[k][j]ならば dist[i][j] = dist[i][k] + dist[k][j] prev[i][j] = prev[k][j]
手続きPath (u, v)は、 prev[u][v] = nullの場合、 []を返します。 パス = [v] u ≠ vの間、 v = prev[u][v] path.prepend(v) 戻りパス
させてなれ頂点の数。すべてを見つけるにはの (すべてのそして) 必要オペレーション。 そして、次のシーケンスを計算します。行列、、、それぞれコストはアルゴリズムの総時間計算量は[ 9 ] [ 13 ]
フロイド・ウォーシャルアルゴリズムは、以下の問題を解決するために使用できます。
多くのプログラミング言語に対応した実装が利用可能です。
非負のエッジ重みを持つグラフの場合、ダイクストラ法は、単一の頂点からすべての最短経路を、実行時間で見つけるために使用できます。したがって、各頂点からダイクストラ法を実行するには時間がかかります。。 以来これにより、繰り返しダイクストラ法の最悪実行時間はこれは、Floyd-Warshall アルゴリズムの漸近的な最悪実行時間と一致するが、関連する定数は非常に重要である。グラフが密である場合(つまり、)、実際には Floyd-Warshall アルゴリズムの方が優れたパフォーマンスを発揮する傾向があります。グラフが疎な場合 (つまり、よりかなり小さい) ダイクストラが優勢になる傾向がある。
負の辺は存在するが負のサイクルが存在しない疎グラフの場合、ジョンソンのアルゴリズムを使用でき、その漸近実行時間は反復ダイクストラ法と同じである。
密なグラフにおける全ペア最短経路計算を高速化するために高速行列乗算を使用する既知のアルゴリズムもありますが、これらは通常、エッジの重みに関して追加の仮定(例えば、小さな整数であることを要求するなど)を置きます。 [ 17 ] [ 18 ]さらに、実行時間に大きな定数係数があるため、非常に大きなグラフの場合にのみ、Floyd–Warshall アルゴリズムよりも高速化されます。