ワーシャルフロイド法
キーワード
概要
重み付きグラフの全ての頂点対間の最短経路を求めるアルゴリズム。 ダイクストラ法と異なり、負の辺があっても動作する。ただし、負の閉路がある場合は正しく動作しない。
最終的に が頂点 から頂点 への最短経路の重みを表すような 行列を得る。
まず次のように を初期化する。
次に、以下のように を更新する。
正当性
回目の反復後の を とする。頂点 を中間点として使って良いとした時の から への最短経路の重みを とする。 このとき、 を について帰納的に示す。
のときは初期値なので明らかに成り立つ。
に対して、 以下では成り立つと仮定する。
アルゴリズムの構成法から、 が成立。( は頂点 を中間点として使って良いとした時の から へのある路の長さ)
従って、 が成り立つことを示せば良い。
頂点 を中間点として使って良いとした時の から への最短路を と置く。( )
が を通らないとすると、 である。帰納法の仮定より、 であり、アルゴリズムの構成法より、 である。従って、 である。
次に、 が を通る場合を考える。
このとき、 と書かれる。 以外の点は のいずれかである。(負閉路を含まないため、同じ点が複数現れることはない)
よって、 が成り立つ。ここで、 は の から の部分路、 は の から の部分路である。
従って、 が言える。
以上より、 が成り立つ。
計算量
グラフの頂点数を とすると、
応用例
実装
func main() {
var n, m int
scanIntVariables(&n, &m)
A := make([][]int, n+1)
for i := 1; i <= n; i++ {
A[i] = make([]int, n+1)
}
for i := 1; i <= n; i++ {
for j := 1; j <= n; j++ {
if i == j {
continue
}
A[i][j] = 1 << 60
}
}
for i := 0; i < m; i++ {
var a, b, c int
scanIntVariables(&a, &b, &c)
A[a][b] = c
}
for k := 1; k <= n; k++ {
for i := 1; i <= n; i++ {
for j := 1; j <= n; j++ {
A[i][j] = min(A[i][j], A[i][k]+A[k][j])
}
}
}
}