一、算法介绍:
Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(All Paris Shortest Paths,APSP)的算法。从表面上粗看,Floyd算法是一个非常简单的三重循环,而且纯粹的Floyd算法的循环体内的语句也十分简洁。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。从本质上说,Floyd是一个动态规划(Dynamic Programming,DP)思想的体现,网上不少文章介绍得很笼统,没有解释清楚基本原理。故在此献上我的想法。
二、Floyd算法:
首先引入一个非常重要的概念:
我们假设Dis(k,i,j)代表着从源点i到终点j的一个最短路径值,且k是该路径中所有点编号的最大值 (而不仅仅只是经过和不经过的问题)。即i到j的路径中所有点的编号都小于等于k。
有了这个概念之后,我们来看看是否能够找出一个迭代关系。
一定的是,对于Dis(k,i,j)的路径中,可能没有包含编号为k的点,也可能包含了编号为k的点,利用这仅有的两种情况可以定义他的迭代关系。
第一种情况下,由于没有经过包含编号k的点,所以Dis(k,i,j) == Dis(k-1,i,j)。
第二种情况下,由于经过了编号为k的点,我们将路径以k点分为两部分Dis(k-1,i,k)和Dis(k-1,k,j),即等式“Dis(k-1,i,k)+Dis(k-1,k,j) == Dis(k,i,j)”成立。由于k作为两部分前者的终点后者的源点,所以两部分中其他的点都应该不大于k-1这个值,所以编号的最大值都是k-1。同等最大编号情况下的两条最短子路径相加必然等于同等最大编号情况下的总路径最小值。
至此,我们在这仅有的两种情况中进行选择,路径更小的就可以更新为源点i终点j且路径中各个点的编号最大值为k的最短路径了( - -真绕口)。即有Dis(k,i,j)=Min{ Dis(k-1,i,k)+Dis(k-1,k,j), Dis(k-1,i,j) }。
现在,我们有了迭代关系,缺少的只有初始条件与结束条件。
对于初始条件,i和j代表各个点,所以取值范围只要在点的编号范围内即可。由于k-1的存在,k的最小值为1。此时有Dis(1,i,j) = Min{ Dis(0,i,1) + Dis(0,1,j), Dis(0,i,j) }。Dis(0,i,j)代表经过点编号最大值为0的点,显然不存在这样的编号