图论-最短路Floyd算法
Floyd(弗洛依德)算法
是动态规划算法,也称插点法。是全源最短路算法。
状态表示
d[k,i,j]表示从i到j,且中间只经过节点编号1~k的最短路径的长度。
状态计算
路径的选择分两种:
- 1.路径不经过k点,继承原值:
d[k,i,j]=d[k-1,i,j] - 2.路径经过k点,松弛操作:
d[k,i,j]=d[k-1,i,k]+d[k-1,k,j]
代码展示
void fioyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
!!!
K一定要在最外层
k放在内层会出错。
因为该算法是通过递归,必须将k-1层的所有状态计算出来后才能得到第k层的值。
不管路径经不经过k点,计算都与k无关,可以省去第一维。
初始化时:
- 如果i,j两点间无边直接相连,d[i][j]初始化为无穷大。
- 如果有边,d[i][j]就是二者边权。
- i=j,自身到自身的距离为0,d[i][j]=0。
枚举完n层后,所有的最短路都会被找出来了。
路径记录与输出
void path(int x,int y)
{
if(p[x][y]==0)return ;
int k=p[x][y];//x.y之间的最短路
path(x,k);
cout<<k<<" ";
path(k,y);
}
完整代码
int d[N][N],p[N][N];
void fioyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(d[i][j]>d[i][k]+d[k][j])
{
d[i][j]=d[i][k]+d[k][j];
p[i][j]=k;
}
}
}
}
}
void path(int x,int y)
{
if(p[x][y]==0)return ;
int k=p[x][y];
path(x,k);
cout<<k<<" ";
path(k,y);
}
floyd()
{
cin>>a>>b;
cout<<a<<" ";
path(a,b);
cout<<b<<" ";
}
时间复杂度:O( n 3 n^3 n3)
例题
B3647 【模板】Floyd
题目描述
给出一张由 n n n 个点 m m m 条边组成的无向图。
求出所有点对 ( i , j ) (i,j) (i,j) 之间的最短路径。
输入格式
第一行为两个整数 n , m n,m n,m,分别代表点的个数和边的条数。
接下来 m m m 行,每行三个整数 u , v , w u,v,w u,v,w,代表 u , v u,v u,v 之间存在一条边权为 w w w 的边。
输出格式
输出 n n n 行每行 n n n 个整数。
第 i i i 行的第 j j j 个整数代表从 i i i 到 j j j 的最短路径。
输入 #1
4 4
1 2 1
2 3 1
3 4 1
4 1 1
输出 #1
0 1 2 1
1 0 1 2
2 1 0 1
1 2 1 0
说明/提示
对于 100 % 100\% 100% 的数据, n ≤ 100 n \le 100 n≤100, m ≤ 4500 m \le 4500 m≤4500,任意一条边的权值 w w w 是正整数且 1 ⩽ w ⩽ 1000 1 \leqslant w \leqslant 1000 1⩽w⩽1000。
数据中可能存在重边。
模板题
Ac代码
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define int long long
#define PII pair<int,int>
#define fi first
#define se second
#define endl '\n'
const int inf=1e18;
const int N=1e6+6;
int n,m;
void solve()
{
cin>>n>>m;
vector<vector<int>>dp(n+1,vector<int>(n+1,inf));
for(int i=1;i<=n;i++)dp[i][i]=0;
for(int i=1;i<=m;i++)
{
int u,v,w;
cin>>u>>v>>w;
dp[u][v]=min(dp[u][v],w);
dp[v][u]=min(dp[v][u],w);
}
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;
}
}
signed main()
{
IOS;
int _=1;
// cin>>_;
while(_--)
solve();
return 0;
}
更多推荐



所有评论(0)