問題描述
輸入:圖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)。