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;
}


更多推荐