为了账号安全,请及时绑定邮箱和手机立即绑定

最短路径问题-Floyd

标签:
算法

最短路径问题

最短路径:

一张图中节点uu到节点vv之间所经过的边权和最小的路径,称为uu,vv之间的最短路径

具体包括下几种类型:
  • 确定起点的最短路问题
  • 确定终点的最短路问题
  • 确定起点和终点的最短路问题
  • 全局最短路问题
常见的解决算法有:
  • FloydFloyd算法
  • DijkstraDijkstra算法
  • SPFASPFA算法

FloydFloyd算法

多源最短路问题:

给出描述图GG的邻接矩阵AA,其中第ii行第jj列的元素AA[ii][jj]代表从第ii个点到第jj个点有一条长度为AA[ii][jj]的有向边,FloydFloyd算法用来计算任意两点之间的最短路

算法描述:

FloydFloyd算法的本质是动态规划

ff[kk][ii][jj]代表只经过前kk个点的从iijj的最短路径,那么ff[00][ ][ ]就是矩阵AA[ ][ ],对于点对(uu,vv)更新到第kk个点的时候,(uu,vv)的最短路径只有两种,一种是经过kk的,一种是没有经过kk的,也就是ff[kk][ii][jj]=min=min{ff[k1k-1][ii][jj],ff[k1k-1][ii][kk]+ff[k1k-1][kk][jj]}。

这样的时间复杂度和空间复杂度都是OO(n3n^{3}),但是我们仔细观察就可以发现,其实三维数组的第一维是没有用的,每一次的更新只是使用第k1k-1层来更新第kk层,并且最后我们所使用的也只是第nn层,所以我们没有必要存储所有的数据,也就是可以简化成ff[ii][jj]=minmin{ff[ii][kk]+ff[kk][jj],ff[ii][jj]},最终的空间复杂度可以降为OO(n2n^{2})的

细节描述:

在知乎上有一个问题叫做“为什么FloydFloyd算法中kk应该放在循环的最外层”。我们要理解FloydFloyd算法的本质是动态规划,kk在某种意义上是一个时间戳,我们使用第k1k-1层的数据来更新第kk层的数据,所以我们必须保证,更新第kk层的时候,k1k-1层的数据已经是最优的。

经典题目:

POJ1125POJ 1125

题意:

每个经纪人有MM个经纪人朋友,给出每个经纪人向其他经纪人传递信息的时间,aa经纪人向bb经纪人传递信息的时间不一定相同,给出所有信息之后,询问从某个经纪人出发,把消息传递给所有经纪人的最小时间,输出这个经纪人的序号,如果有一个或者一个以上的经纪人无法接收信息,输出"disjointdisjoint"

题解:

找到所有点对之间的最短路径

代码实现:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 0x3f3f3f3f
using namespace std;

const int maxn=100+5;
int n,dis[maxn][maxn];

inline int read(void){
  char ch=getchar();
  int f=1,x=0;
  while(!(ch>='0'&&ch<='9')){
      if(ch=='-') f=-1;
      ch=getchar();
  }
  while(ch>='0'&&ch<='9')
    x=x*10+ch-'0',ch=getchar();
  return f*x;
}

signed main(void){
  while(n=read()){
    memset(dis,inf,sizeof(dis));
    for(int i=1,m,x;i<=n;i++){
      m=read();
      for(int j=1;j<=m;j++)
        x=read(),dis[i][j]=read();
    }
    for(int i=1;i<=n;i++)
      dis[i][i]=0;
    for(int k=1;k<=n;k++)
      for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
          dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
    int ans=inf,node;
    for(int i=1;i<=n;i++){
      int Max=0;
      for(int j=1;j<=n;j++)
        Max=max(Max,dis[i][j]);
      if(ans>Max)
        ans=Max,node=i;
    }
    if(ans==inf)
      cout<<"disjoint"<<endl;
    else
      cout<<node<<" "<<ans<<endl;
  }
  return 0;
}
传递闭包问题
问题描述:

求一张图中所有点对之间的路径互达问题

Floyd算法的应用:

我们可以把所有没有直接路径相连的点对之间的边权设为infinf,其他有直接路径相连的点对之间的边权设为11,那么如果最终两个节点之间的最短路径为infinf,就代表其之间不可互达

代码实现:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=100+5;
int n,m,mp[maxn][maxn],cnt[maxn],ans;
signed main(void){
	memset(mp,0,sizeof(mp)),ans=0,memset(cnt,0,sizeof(cnt));
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++)
		scanf("%d%d",&x,&y),mp[x][y]=1;
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(mp[i][k]&&mp[k][j])
					mp[i][j]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(mp[i][j]||mp[j][i])
				cnt[i]++;
	for(int i=1;i<=n;i++)
		if(cnt[i]==n-1)
			ans++;
	cout<<ans<<endl;
	return 0;
}
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消