最短路最基本算法———Floyd算法
关于floyd算法
- 算法简介
- 实现思想
- 核心代码
- 后记
一、floyd简介
引自百度百科
在计算机科学中,Floyd-Warshall算法是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法。算法的单个执行将找到所有顶点对之间的最短路径的长度(加权)。 虽然它不返回路径本身的细节,但是可以通过对算法的简单修改来重建路径。 该算法的版本也可用于查找关系R的传递闭包,或(与Schulze投票系统相关)在加权图中所有顶点对之间的最宽路径。
是不是觉得很高深?没错,这段介绍并没有什么多大的用。
换而言之
floyd就是一种求最短路的算法,最基础的算法
优点: 代码简短,易于理解,可用于负边权,可求所有点之间的距离
缺点: 时间复杂度爆炸
实现思想
其实floyd是利用dp的思想实现的,不断寻找中间点求最优解
枚举起始点,中点和终点,利用中点不断对不同的起点终点进行松弛操作,
更新任意两点之间的最优子答案,最后得到最优解
核心代码
for(int k=1;k<=n;k++)//枚举中点
{
for(int i=1;i<=n;i++)//枚举起点
{
for(int j=1;j<=n;j++)//枚举终点
{
if(i!=j&&i!=k&&j!=k) //三点不是相同的点时
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);//利用中点进行松弛操作
}
}
}
是不是很easy
后记
如果你看到了这个后记,那你还是幸运的,你马上看到的才是floyd算法中最重要的东西
你是否发现,或者有疑问,floyd的操作,如何能保证能得到最优解,而不是被埋没在次优解里,
或者说你疑问为什么最外层循环是枚举k,因为这样才能保证这个算法的正确性
还记得开始的介绍的实现思想么
没错,动态规划
我们设dis [ k ] [ i ] [ j ] 表示i和j之间可以通过编号为1…k的节点的最短路径。
那么则dis [ k ] [ i ] [ j ] 可以从dis [ k -1 ] [ i ] [ j ] 转移来,表示i到j不经过k这个节点。
也可以从dis [ k - 1 ] [ i ] [ k ] + dis [ k - 1 ] [ k ] [ j ] 转移过来,表示经过k这个点。
意思即dis [ k ] [ i ] [ j ] = min ( dis [ k - 1 ] [ i ] [ j ] ,dis [ k - 1 ] [ i ] [ k ] +dis [ k - 1 ] [ k ] [ j ] )
然后我们能发现我们能dis的第一维k是可以省略的,因为k只和k-1有关(就和背包问题中0/1背包和完全背包的一维优化一个原理)
所以当前的dis [ i ] [ j ] 都应该是完成上一层动态规划的,如果k不是在最外层,那么dis [ i ] [ j ] 就不是完成上一层动态规划的后的状态,有可能有的点没有经过k-1这个点的松弛。
所以k要放在最外面
可以参考
传送门
floyd虽然是最短路算法中最简单基础的一个,但永远不要小看任何一个算法,每种算法都有着自己的智慧
So it is