之前一直以为Floyd就是普通的三重循环暴力,今天才懂蕴含着动态规划的思想
题目思路
g[k][i][j]
数组含义:从1
到k
的节点作为中间经过的节点时,从i
到j
的最短路径长度。- 状态转移方程
g[k][i][j] = min(g[k-1][i][j] , g[k-1][i][k] + g[k-1][k][j])
,表示g[k][i][j]
①经过1
到k-1
,不经过k
节点;②不经过1
到k-1
,经过k
节点。 - 根据动态规划,
g[k]
只可能与g[k-1]
有关系,所以可以省略最外层的维度k,直接带入循环求解。
C++代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 210;
int n, m, k;
int g[N][N];
void Floyd()
{
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin >> n >> m >> k;
memset(g, 0x3f, sizeof g);
for (int i = 1; i <= n; i++)
{
g[i][i] = 0;
}
while (m--)
{
int a, b, w;
cin >> a >> b >> w;
g[a][b] = min(g[a][b], w);
}
Floyd();
while (k--)
{
int a, b;
cin >> a >> b;
if (g[a][b] > 0x3f3f3f3f / 2)
{
cout << "impossible" << endl;
}
else
{
cout << g[a][b] << endl;
}
}
return 0;
}