网上讲floyd算法的不少,不过都知道这是动态规划算法的应用,我却没看到几个说明白的,又是那种给你证明这么做是对的的方式,或者还有从前往后推不断加入中介点的,看着貌似正确,实际上根本没体现动态规划的思想所在.
动态规划算法,那自然是从后往前推才对,我就从后往前推来说明一下怎么推导出floyd算法的,即正常的思考过程,不是证明过程.
假设有5个点,1,2,3,4,5.我想求1到5的最短路径.
okay,根据动态规划的思想,从后往前推,那么类似背包问题,我们考虑对可能的最短路径进行情况划分:①最短路径包含4 ②最短路径不包含4
分析①:
最短路径包含4,那么这路径分为两段,第一段:1通过[1,2,3]到达4的最短路径;第二段:4通过[1,2,3]到达5的最短路径.注意中间点集合为[1,2,3],没有5,因为有5的话那就“绕路”了.
另外这里的1通过[1,2,3]到达4并不意味着中间点1,2,3全在路径上(当然1作为源点肯定在),只是表明这是可供选择的中间点的集合.
分析②:
最短路径不包含4,那就直接1通过[1,2,3]到达5的最短路径.
回头看看原问题的表述:1到5的最短路径.即1通过[1,2,3,4]到达5的最短路径.
数学化的表达一下:
L(1,[1,2,3,4],5)=min{ L(1,[1,2,3],4)+L(4,[1,2,3],5),L(1,[1,2,3],5) }.
okay,看到什么了?左边是[1,2,3,4],右边清一色的[1,2,3]。
没错![1,2,3,4]被分解为了几个[1,2,3],子问题规模变小了,动态规划目的达到了。
要是觉得还不够清楚,再分解一下L(1,[1,2,3],4)
L(1,[1,2,3],4)=min{ L(1,[1,2],4)+L(3,[1,2],4),L(1,[1,2],4) }.
看到了吗?有3没3的两种路径都会分解为[1,2].从[1,2,3]又分解为了[1,2].
这样下去,[1,2,3,4]->[1,2,3]->[1,2]->[1]->[].
实际上以上状态转移方程写的还有一点小瑕疵,[1,2,3,4]应该放在括号最左边.
假设源点为i,终点为j,中间点集合的元素数为k.
那么为了求解k=4时的状态,我们需要求解所有k=3的状态,
为了求解k=3时的状态,我们需要求解所有k=2的状态。。。
所谓所有k=3的状态,就是{i:1到5变化,j:1到5变化.k=3} 对应的各种状态.
所以k应该放在最左边,因为它是最外层循环.
L([1,2,3,4],1,5)=min{ L([1,2,3],1,4)+L([1,2,3],4,5),L([1,2,3],1,5) }.
嗯,就是这样.