PS:本文是在他人博文基础上加以修改而来,将从 Ak(i,j) 推导 Ak-1(i,j) 改为从 Ak-1(i,j) 推导 Ak(i,j),为的是符合自己的思维习惯,更好的理解floyd算 法,并且方便以后查看。
在此首先对原作者表示感谢!
原文地址——http://blog.csdn.net/roofalison/article/details/5651806
下面进入正文
floyd的代码实现其实很简单:
-
void floyd() -
{ -
for(k=0;k<n;k++) -
for(i=0;i<n;i++) -
for(j=0;j<n;j++) -
A[i][j]=min(A[i][j],A[i][k]+A[k][j]); -
}
floyd算法是一个经典的动态规划算法,目标是寻找从点i到点j(图中任意两点)的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)。假设图有n个顶点,依次为0,1,…,n-1,floyd算法加入了这个概念
Ak(i,j):表示从顶点i到顶点j且中间顶点的序号不大于K的最短路径。
这个限制的重要之处在于,它将最短路径的概念做了限制,使得该限制有机会满足迭代关系,这个迭代关系就在于研究:假设Ak-1(i,j)已知,是否可以借此推导出Ak(i,j)。针对此问题,采用数学归纳法,我们分两步解决:
1、由Ak(i,j)的定义可得初始状态(即中间不经过其他任何顶点):A-1(i,j) = cost(i,j)。(cost(i,j)为连接顶点i 和顶点j 的边的权值,若两顶点间无边,则值为无穷大)
2、假设此时Ak-1(i,j)已知,并且在此基础上求解Ak(i,j),那么我们可以分两种情况来看待这个问题:1. Ak(i,j)沿途经过点k;2. Ak(i,j)不经过点k。如果经过点k,那么很显然,Ak(i,j) = Ak-1(i,k) + Ak-1(k,j)。为什么是Ak-1呢?因为Ak-1是我们目前得到的最优解。那么遇到第二种情况,Ak(i,j)不经过点k时,由于没有经过点k,所以根据概念,可以得出Ak(i,j)=Ak-1(i,j)。现在,我们确信有且只有这两种情况—不是经过点k,就是不经过点k,没有第三种情况了,条件很完整,那么是选择哪一个呢?很简单,求的是最短路径,当然是哪个最短,求取哪个,故得出式子:
Ak(i,j) = min( Ak-1(i,j), Ak-1(i,k) + Ak-1(k,j) )
到这里,已经列出了求取Ak(i,j)的整个算法了,但是,最终的目标是求dist(i,j),即i到j的最短路径,如何把Ak(i,j)转换为dist(i,j)?这个其实很简单,当k=n-1(n表示图中顶点的个数)的时候,即是说,An-1(i,j)=dist(i,j)。那是因为当k已经最大时,已经不存在索引比k大的点了,那这时候的An-1(i,j)其实就已经是顶点i 到顶点j 的最短路径了。
从动态规划算法设计的角度来讲,求解决策过程的最优化问题,首先应将待求解问题分解成若干个子问题,确定待求解问题与子问题的定量关系,先求解子问题,然后从这些子问题的解得到原问题的解。而本文可看做求解定量关系部分(即由子问题出发,求解原问题)。
个人总结:划分的过程是从上往下,求解的过程是从下往上。