Appearance
ワーシャルフロイド法(Warshall-Floyd)
すべての頂点間の最短距離を O(V³) で求めるアルゴリズム。
負辺があっても利用でき、負閉路の検出も可能。
特徴
| 項目 | 内容 |
|---|---|
| 用途 | 全点対最短経路 |
| 適用条件 | 負辺も可 |
| 計算量 | O(V³) |
| 空間計算量 | O(V²) |
考え方
dist[i][j] を頂点 i から j への最短距離とする。
頂点 k を経由する場合としない場合を比較し、距離を更新する。
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
これをすべての k, i, j について繰り返す。
実装
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1LL << 60;
int main() {
int n, m;
cin >> n >> m;
vector<vector<ll>> dist(n, vector<ll>(n, INF));
for (int i = 0; i < n; i++) dist[i][i] = 0;
for (int i = 0; i < m; i++) {
int a, b;
ll w;
cin >> a >> b >> w;
dist[a][b] = min(dist[a][b], w);
}
auto warshall_floyd = [&]() {
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
if (dist[i][k] == INF) continue;
for (int j = 0; j < n; j++) {
if (dist[k][j] == INF) continue;
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
};
warshall_floyd();
for (int i = 0; i < n; i++) {
if (dist[i][i] < 0) {
cout << "NEGATIVE CYCLE\n";
return 0;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j) cout << ' ';
if (dist[i][j] == INF) cout << "INF";
else cout << dist[i][j];
}
cout << '\n';
}
}使用例
入力(0-indexed、有向グラフ)
text
4 4
0 1 2
0 2 10
1 2 -1
2 3 3出力
text
0 2 1 4
INF 0 -1 2
INF INF 0 3
INF INF INF 0dist[i][j] で、頂点 i から頂点 j への最短距離を取得できる。
注意点
- 初期状態では
dist[i][i] = 0、それ以外はINFにする。 - 辺が複数存在する場合は、最小の重みを採用する。
INF同士などを加算しないように、到達可能性を確認する。- 負辺があっても使用できるが、負閉路の影響を受ける頂点間の最短距離は定義できない。
dist[i][i] < 0となる頂点があれば、負閉路が存在する。- 無向グラフの場合は逆向きの辺も追加する。
- O(V³) なので頂点数が大きい場合は厳しい。
- 距離の加算によるオーバーフローに注意する。