一、概述:
(1)floyd算法是基于动态规划思想的一种最短路算法
(2)floyd用于处理多源汇最短路问题,也可以处理单源最短路,但是因为其时间复杂度较高,所以单源最短路一般还是选用其他算法
(3)floyd不能处理有负权回路的最短路问题
二、实现:
(1)建立一个dp数组:g[k][i][j],其含义是从点i到点j,允许经过编号为1~k的点的路径的最小值
(2)g[0][i][j]是后面进行动态规划的初始状态,表示从点i到点j,中间不经过任何其他的点,所以应该初始化为正无穷;如果i和j之间有边,那么就赋值为边权的值;如果i==j,那么就赋值为0
(3)状态转移方程为:(表示不经过点k和经过点k)
g[k][i][j]=min(g[k-1][i][j],g[k-1][i][k]+g[k-1][k][j])
四、代码示例:
例题: AcWing 854. Floyd求最短路 - AcWing(已做笔记)
(1)未压缩三维数组版本
#include <iostream>
#include <cstring>
#include <algorithm>
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f,N=210;
int n,m,q;
int g[N][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[k][i][j]=min(g[k-1][i][j],g[k-1][i][k]+g[k-1][k][j]);//经过点k和不经过点k
}
}
}
}
int main()
{
cin >> n >> m >> q;
//只对第一层初始化即可
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) g[0][i][j]=0;//自己到自己就初始化为0
else g[0][i][j]=INF;
}
}
while(m--){
int a,b,c;
cin >> a >> b >> c;
g[0][a][b]=min(g[0][a][b],c);//重边取最小
}
floyd();
while(q--){
int a,b;
cin >> a >> b;
if(g[n][a][b]>INF/2) cout << "impossible" << endl;
else cout << g[0][a][b] << endl;
}
return 0;
}
(2)滚动数组优化版本
做等价变形即可
#include <iostream>
#include <cstring>
#include <algorithm>
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f,N=210;
int n,m,q;
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]);//经过点k和不经过点k
}
}
}
}
int main()
{
cin >> n >> m >> q;
//因为是二维的,所以初始化一层等于初始化全部
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) g[i][j]=0;//自己到自己就初始化为0
else g[i][j]=INF;
}
}
while(m--){
int a,b,c;
cin >> a >> b >> c;
g[a][b]=min(g[a][b],c);//重边取最小
}
floyd();
while(q--){
int a,b;
cin >> a >> b;
if(g[a][b]>INF/2) cout << "impossible" << endl;
else cout << g[a][b] << endl;
}
return 0;
}