多源最短路径算法(竞赛)
一、思路
和松弛思想一样,任意两点之间的最短距离不可能全是直接的从 i 到 j,一定会有中间节点,所以我们设任意两点最短路径之间存在 k 个节点,分别遍历出 k 从 1 到 n 节点最小路径值那就是 ij 两点之间的最短路径算法。
dp 方程:
不选中间节点:dp[k][i][j] = dp[k - 1][i][j];
选中间节点 k:dp[k][i][j] = dp[k - 1][i][k] + dp[k - 1][k][j];
这一层的k完全依赖于上一层的k - 1,所以变成二维
因为要取min,而且一开始ij不知道多长,所以不知道的ij是无穷,ii才是0
二、例题
B3647 【模板】Floyd - 洛谷
#include "bits/stdc++.h"
using namespace std;
int n, m;
const int N = 110;
const int INF = 0x3f3f3f3f;
// 要求ij距离,i直接到j不一定是最短距离,所以要在ij之间添加k个节点,逐渐计算
// i ... k1 ... k2 ... j中最短的那个距离,所以是k从1开始遍历,每添加一个k就取一次min
// 不选中间节点:dp[k][i][j] = dp[k - 1][i][j];
// 选中间节点 k:dp[k][i][j] = dp[k - 1][i][k] + dp[k - 1][k][j];
// 这一层的k完全依赖于上一层的k - 1,所以变成二维
// 因为要取min,而且一开始ij不知道多长,所以不知道的ij是无穷,ii才是0
void F()
{
vector<vector<int>> dp(n + 1, vector<int>(n + 1, INF));
while(m--)
{
int u, v, w;
cin >> u >> v >> w;
// 取min防止给我重复的大的权值
dp[u][v] = dp[v][u] = min(dp[u][v], w);
}
for(int i = 1; i <= n; i++)
dp[i][i] = 0;
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cout << dp[i][j] << ' ';
}
cout << endl;
}
}
int main()
{
cin >> n >> m;
F();
return 0;
}