深入理解Floyd算法思路

Floyd算法经典代码只有5行(或者也可以写成4行),思路听起来也那么“显然”。

但大部分人对Floyd算法的理解仅仅限于它的实现是三层循环,k在最外层,i和j在内层不分顺序,用路径松弛来更新最短路径。但其实大多数人都没有弄清楚一个问题,为什么外层循环是遍历k,而不是把k放到最内层呢,只是知道放在里边就不对了。当然,也有不少博客解释这个问题,但写的大多有些复杂,下面是我个人的理解。

首先,它是运用了动态规划的思想来进行问题求解。动态规划解题的关键在于找好子结构。Floyd构造的结构非常巧妙:找i和j之间通过编号不超过k(k从1到n)的节点的最短路径(一定要注意,这里是当前最短路径,当k=n时达到最终最短路径)。为了便于说明,我们可以弄一个三维数组f[k][i][j]表示i和j之间可以通过编号不超过k的节点的“最短路径”。对于k-1到k,只有两种可能,经过编号为k的点,要么不能找到一条从i到j的更短路,此时有f[k][i][j] = f[k-1][i][j] ;要么能找到,那这个最短路径一定是d[i][k]+d[k][j],那么就用这个较小的距离去更新d[i][j]。综合以上两种情况,f[k][i][j] = min(f[k-1][i][j] , f[k-1][i][k]+f[k-1][k][j])。

具体实现就比较简单了,对任意两点间的距离,我们初始化他们为无穷大(这里无穷大是一种形象的说法),然后用松弛技术进行距离的更新。然后用三层循环的话,最外层空间就可以省下来了,因为f[k]只与f[k-1]有关。

好啦,下面给一个Floyad算法经典水题。

#include
#include
#include
using namespace std;
const int N = 100;
int map[N][N],n,m;
int main()
{
	int x,y,z;
	scanf("%d%d",&n,&m);
	memset(map,0x3f,sizeof(map));
	/*for(int i=0;ifor(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(map[i][j] > map[i][k] + map[k][j])
				{
					map[i][j] = map[i][k] + map[k][j];
				}
			}
		}
	}
	while(scanf("%d%d",&x,&y))
	{
		printf("%d\n",map[x][y]);
	}
	return 0;
}



你可能感兴趣的:(算法专题)