最短路最基本算法———Floyd算法

关于floyd算法

  1. 算法简介
  2. 实现思想
  3. 核心代码
  4. 后记

一、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的操作,如何能保证能得到最优解,而不是被埋没在次优解里,
或者说你疑问为什么最外层循环是枚举k,因为这样才能保证这个算法的正确性

还记得开始的介绍的实现思想么
没错,动态规划
我们设dis[k][i][j]dis [ k ] [ i ] [ j ] 表示iijj之间可以通过编号为1…k的节点的最短路径。
那么则dis[k][i][j]dis[k1][i][j]dis [ k ] [ i ] [ j ] 可以从dis [ k -1 ] [ i ] [ j ]转移来,表示iijj不经过kk这个节点。
也可以从dis[k1][i][k]+dis[k1][k][j]dis [ k - 1 ] [ i ] [ k ] + dis [ k - 1 ] [ k ] [ j ] 转移过来,表示经过k这个点。
意思即dis[k][i][j]=min(dis[k1][i][j],dis[k1][i][k]+dis[k1][k][j])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]dis [ i ] [ j ] 都应该是完成上一层动态规划的,如果k不是在最外层,那么dis[i][j]dis [ i ] [ j ] 就不是完成上一层动态规划的后的状态,有可能有的点没有经过k-1这个点的松弛。

所以k要放在最外面

floyd虽然是最短路算法中最简单基础的一个,但永远不要小看任何一个算法,每种算法都有着自己的智慧

posted @ 2018-07-31 17:02  Stargazer_cykoi  阅读(130)  评论(0编辑  收藏  举报