问题描述
输入:图G = (V,E)
输出:图中任意两点的最短路径
算法描述(Floyd算法)
1. 分析优化子结构
定理1,Vi,Vj的最短路径包含两点Vm,Vn,那么Vi,Vj的最短路径中对应Vm,Vn的部分一定是Vm,Vn在该图中的一条最短路径。
证明1,可以通过反证法进行证明,如果不是,那么可以构造出比当前Vi,Vj的最短路径更短的路径。
2. 分析子问题重叠性。
首先,需要了解Vi,Vj的递归代价方程。
定义:D(i,j)为Vi,Vj的最短路径长度。
- D(i,j) = 0,if i = j.
- D(i,j) = min ( D(i,j) , D(i,k) + D(k,j)),其中,i ≤ k ≤ j,if i ≠ j.
那么此问题的计算形式基本上于矩阵链乘问题的计算形式,这就是一个划分动态规划,那么同理自然就有子问题重叠性。
3.递归地定义最优解的代价
- D(i,j) = 0,if i = j.
- D(i,j) = min ( D(i,j) , D(i,k) + D(k,j)),其中,i ≤ k ≤ j,if i ≠ j.
4.自底向上地计算优化解的代价保存之,并获取构造最优解的信息
对于该算法而言,计算顺序是值得思考的。如果直接进行遍历计算,可能当计算D(i,j)时,所使用的D(i,k)以及D(k,j)都并非是最小代价,可以说,每个D(i,j)都相互影响。
解决办法为:构建顶点集合S以及表示任意两点之间最小路径代价的二维矩阵M,
- 初始时,S为空,M中仅仅将边录入,无边记为无穷。
- 依次向S中加入顶点,并仅仅将该顶点作为递归方程中的顶点Vk,更新M。
- 当S = V时,M中记为最短路径代价。
故而可以设计算法为:
Floyd算法
D <-- W
P <-- 0
For k = 1 to n Do /*k控制填入元素*/
For i = 1 to n Do /*i,j控制矩阵的遍历*/
for j = 1 to n
if (D[ i, j ] > D[ i, k ] + D[ k, j ] )
then D[ i, j ] = D[ i, k ] + D[ k, j ]
P[ i, j ] = k;
5.根据构造最优解的信息构造优化解
注意,下列算法只打印中间节点,而不会答应起止节点,所以,P中无边或者直接有边的值均为0.
path(index q, r)
if (P[ q, r ]!=0)
path(q, P[q, r])
println( “v”+ P[q, r])
path(P[q, r], r)
return;
//no intermediate nodes
else return
6.算法复杂性分析:
时间复杂性:
计算代价的时间复杂性:O(n^3)。
构造最优解时间复杂性:O(n)。最多只会遍历n个顶点
空间复杂性:O(n^2)。