多元最短路-Floyd演算法
題目描述
時間限制:5.0s 記憶體限制:256.0MB
問題描述
給定\(n\)個結點兩兩之間的單向邊的長度,求兩兩之間的最短路徑。
輸入格式
輸入第一行包含一個整數\(n\),表示點數。
接下來\(n\)行,每行包含\(n\)個整數,第\(i\)行表示第\(i\)個點到每個點的邊的長度,如果沒有邊,則用\(0\)表示。
輸出格式
輸出\(n\)行,第\(i\)行表示第\(i\)個點到其他點的最短路徑長度,如果沒有可達的路徑,則輸出\(-1\)。
樣例輸入
3
0 1 0
0 0 6
0 2 0
樣例輸出
0 1 7
-1 0 6
-1 2 0
資料規模和約定
\(1\leq n\leq 1000\),\(0<\)邊長\(\leq 10000\)。
解析
Floyd 演算法:
\(a_{ij} 表示\)i\(到\)j\(之間的邊長,當\)i\(到\)j$之間沒有變時取無限大.
\(f_{kij}\) 表示\(i\)到\(j\)允許使用節點\(1~k\)作為中間節點.
目標:\(f_{nij}\)
初值:\(f_{0ij} = a_{ij}\) 表示從\(i\)到\(j\)不允許經過其他節點作為中間節點,所以\(i\)到\(j\)的距離就是\(a_{ij}\)。
轉移方程:$f_{kij} = min(f_{k-1ij}, f_{k-1ik} + f_{k-1kj})
不用k點作為中間節點 用
因為用三維陣列記憶體超大,需要優化
優化:
可以壓縮一個維度————k
可以使用滾動陣列,只需f[2][n][n],大大減小了陣列記憶體佔用
於是f[k % 2][i][j] = min(f[(k - 1) % 2][i][j], f[(k - 1) % 2][i][k] + f[(k - 1) % 2][k][j])
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int INF = 1e9; int a[1005][1005]; int f[2][1005][1005]; int main(int argc, char** argv) { int n; cin >> n; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { cin >> a[i][j]; if (a[i][j] != 0) f[0][i][j] = a[i][j]; else if (i != j) f[0][i][j] = INF; } for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) f[k % 2][i][j] = min(f[(k - 1) % 2][i][j], f[(k - 1) % 2][i][k] + f[(k - 1) % 2][k][j]); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (f[n % 2][i][j] == INF) cout << -1 << " "; else cout << f[n % 2][i][j] << " "; } cout << endl; } return 0; }