【C++】Floyd算法

670 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」。

算法简介

FloydFloyd算法是多源最短路径算法,即可以求任意两点的最短路径,它基于动态规划的思想,时间复杂度为O(n3)O(n^3)。 它的创始人罗伯特·弗洛伊德(Robert WFloyd)(Robert\ W.Floyd)将此算法命名为FloydWarshallFloyd-Warshall算法,简称FloydFloyd算法。罗伯特·弗洛伊德是1978年图灵奖得主,他同时还创立了堆排序算法。

算法思想

FloydFloyd算法的核心思想就是用每个点作为中间结点去更新任意点的最短路径。

它的核心思想是dp[k][i][j]=min(dp[k1][i][j],dp[k1][i][k]+dp[i1][k][j])dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[i-1][k][j])

其中dp[0][i][j]=map[i][j]dp[0][i][j]=map[i][j]也就是初值为邻接矩阵。

核心代码

假设目前map[0][ ][ ]map[0][\ ][\ ]存的是邻接矩阵。

void Floyd(){
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				map[k][i][j]=min(
					map[k-1][i][j],
					map[k-1][i][k]+map[k-1][k][j]
				);
			}
		}
	}
}

值得注意的是kk在最外层,这是因为FloydFloyd本质是动态规划算法,做的实际上是二维动态规划。第一个维度的kk只表示第kk次动态规划的结果,而第二个第三个维度的kk则表示以第kk个点作为中间结点。

优化

FloydFloyd算法可以在空间上进行优化,这才是平常使用的FloydFloyd算法。 dp[k][i][j]=min(dp[k1][i][j],dp[k1][i][k]+dp[i1][k][j])dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[i-1][k][j])中,在第kk轮时,与kk相关的路径长度是不会改变的,所以无需保存前一个状态。

void Floyd(){
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				map[i][j]=min(
					map[i][j],
					map[i][k]+map[k][j]
				);
			}
		}
	}
}

总结

FloydFloyd算法的因为要求任意两点最短路径,所以空间复杂度就是存图的O(n2)O(n^2),因为三重循环则导致了时间复杂度为O(n3)O(n^3)FloydFloyd算法适用于带负权的图,但不能出现负权环。因此,FloydFloyd算法不适用于大量数据的计算,他简单易实现的同时也注定了效率上得做取舍。