1. 程式人生 > 其它 >多元最短路-Floyd演算法

多元最短路-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;
}