1、状态表示:fkij 表示:仅仅经过 1, k 这些点建起的桥梁,结点 i 走到结点 j 的最短路径的长度。
2、状态转移方程:
📌第一种情况:不选新来的点(不走刚刚建起的桥梁,从起点 i 走到 终点 j ,只走编号为 1 ~ k - 1 的桥梁):fkij = fk - 1ij;
📌第二种情况:选新来的点(走刚刚新建起的桥梁,从起点 i 走到终点 j ,以编号为 k 的桥梁为中转,划分成 i 到 k 、k 到 j 两段,这两段行程可走的桥梁范围都是:1 ~ k - 1):fkij = fk - 1ik + fk - 1kj;
📌最终是求两种情况的 min 。
3、空间优化:
dp 表 f 数组本身是三维的,让桥梁 k 那一维作 z 轴,我们可以发现,k = 0 的那一层是初始化的时候,k = n 的那一层是最终结果的时候,当前层的结果是根据上一层的结果递推的,所以可以空间优化、删掉第一维,而且,根据 k 值的不同,每一层更新出来的结果根据状态表示含义都有着自己的意义,比如:k = 4 的时候,f4ij 表示的是:从起点 i 到 终点 j 只经过 编号为1 ~ 4的桥梁 的最短路径长度。
4、初始化:
和邻接矩阵的初始化几乎一摸一样。
📌fii = 0;自己到自己的最短路径是 0.
📌fij 为初始状态下 i 到 j 的距离,如果 i、j 之间没有边,距离则是无穷。
5、填表顺序
一定先枚举 k ,再枚举 i 和 j ,因为当前第 k 层的更新,靠的都是 k - 1 层的状态来的。
6、最终结果:
dp 表里面存着。
OJ题来源:洛谷
OJ题名:【模板】Floyd
OJ题归属:图论基础【多源最短路】
解题算法:Floyd 算法。
cpp复制代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 110;
int n, m;
int f[N][N];
int main()
{
cin >> n >> m;
// 初始化
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; i++) f[i][i] = 0;
for (int i = 1; i <= m; i++)
{
int u, v, w; cin >> u >> v >> w;
// 重边
f[u][v] = f[v][u] = min(f[u][v], w);
}
// Floyd
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << f[i][j] << " ";
}
cout << endl;
}
return 0;
}