Floyd 多源最短路径算法

为求出一个无向图每一个点之间的最短距离,就可以使用到Floyd算法。
首先,把每一条最短路径表示为 dis[i,j] ,接着就需要求出每一个点到其他点的算法。
例如这样的一个图
Floyd 多源最短路径算法 - 赵子睿 - 赵子睿的博客
要求出每一个节点之间的距离,首先想到的自然是BFS,但是这样的速度太慢,所以,就需要引出Floyd算法了。
Floyd的本质是DP的一种。
每一个节点到另外一个的长度自然可以表示为i到其中一个中间节点的距离加上这个中间节点到另一个节点的距离之和。
所以,以此可以把每一条边的距离分解为两条边。最短路径同样是这样,就形成了DP的一种基本模型,化解为子问题。
那么它的状态是什么呢?答案就是这一个中间节点。如果这一条边不存在,那么得到的答案自然也不成立。
每两点的最短路径肯定是自己目前已经具有的距离与自己到其他的每一个点的距离之和作比较,取得最小值。
所以,我们可以得到状态转移方程f[i,j][k]=min(f[i,j][k-1] , f[i,k][k-1]+f[k,j][k-1])
储存肯定是需要三维数组的,但是很容易爆空间。
所以,可以发现,最后查询时只需要查询最后一个数组,而且在生成时只需要查询前一个数组,那么就可以使用滚动数组来实现。
但是实际上,是可以使用一个数组来实现的,因为每一次修改,都会导致这一个变得更优,再一次调用,会得到更优的答案,实际上反而还稍微减少了时间,而不会影响到结果。
但是,这要怎么实现呢?
首先肯定是需要需用到三重循环的。
是for i for j for k ……吗?
答案是不是的。因为当每一次修改之后,i到k节点的距离和k到j的距离都会变化,产生更优的答案,所以三重循环是不行的,只有到当前一次所有的长度都没有修改为止。
那么,有更优的方案吗?
答案肯定是有的。答案就是将for k……移动到最外一重循环中。
怎么证明呢?
因为使用一个数组来计算,如果k每一次都变化,比i和j变化的都快,就会导致后面有一组i,j;j,k优化了当前方案,而且这一个方案也会影响到前面,就会产生重复计算。所以,让k运行时不会处理完5之后再处理2的情况出现,就避免了重复计算。所以,k需要作为最外层的循环。
最后查询时直接输出f[i][j]就可以了。

参考程序:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>

using namespace std;

const int INF=0x7ffffff;
int dis[500][500];
int n,m;

int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i == j) dis[i][j]=0;
else dis[i][j]=INF;//一开始把所有边设置为不存在

for(int i=0;i<m;i++)
{
int len,pointx,pointy;
scanf("%d%d%d",&pointx,&pointy,&len);

dis[pointx][pointy]=len;
dis[pointy][pointx]=len;//链接两个节点
}

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][j],dis[i][k]+dis[k][j]);//DP求最小路径

int Nedge;
scanf("%d",&Nedge);
for(int i=0;i<Nedge;i++)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",dis[u][v]);//查询最小路径
}

return 0;
}


最后评价一下Floyd,这一个算法的空间复杂度是O(N^2),但是时间复杂度却达到了O(N^3)N为边数。
所以,当N超过了400,就很容易超时。但是,这一种算法,对于稠密图来说,是比较快的。而且编起来也比dijkstra容易的多。所以,当点数少时,哪怕是单源最短路径,也是算很快的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值