演算法導論筆記:25所有節點對的最短路徑問題
本章考慮在給定的有向加權圖G=(V, E),對於所有的節點u,v∈V,找到一條從節點u到節點v的最短路徑。希望以表格的形式表示輸出:第u行第v列給出的是節點u到節點v的最短路徑權重。
對於這個問題,如果是執行|V|次單源最短路徑演算法來解決所有節點對的最短路徑問題,每一次使用一個不同的節點做為源節點。如果所有邊的權值是非負的,可以採用Dijkstra演算法。如果採用陣列來實現最小優先佇列,演算法的執行時間為O()=O()。使用二叉堆實現的最小優先佇列將使演算法的執行時間降低到O(VE
lg V),這個時間在稀疏圖的情況下有很大改進,因為稀疏圖E <。如果採用斐波那契堆來實現最小優先佇列,其演算法執行時間為O(
如果圖中有權重為負值的邊,就必須採用效率更低的Bellman-Ford演算法,這樣的執行時間將使O(),在稠密圖的情況下,該執行時間為O()。
本章研究的演算法將能做到更好,同時,本章還討論所有節點對最短路徑問題與矩陣乘法之間的關係。
本章的多數演算法採用鄰接矩陣表示圖,假定節點的編號為1,2,...,|V|,因此,演算法的輸入是n*n的矩陣W,該矩陣代表一個有n個節點的有向圖的邊的權重:
演算法的輸出也是一個n*n的矩陣D = ()。其中 = δ(i, j)。
為了解決所有頂點間最短路徑問題,不僅要算出最短路徑的權值,而且要計算出一個前驅節點矩陣
PRINT-ALL-PAIRS-SHORTEST-PATH(, i, j)
if i == j
print i
else if == NIL
print “no path from i to j exists”
else PRINT-ALL-PAIRS-SHORTEST-PATH(
print j
本章使用大寫字母表示矩陣,如W, L或D,使用帶下標的小寫字母表示矩陣中的個體元素,如、或。
一:最短路徑和矩陣乘法
本節討論一種動態規劃演算法,動態規劃演算法的步驟是:分析最優解的結構,遞迴定義最優解的值,自底向上計算最優解的值。
之前討論單源最短路徑問題時,已經證明一條最短路徑的所有子路徑都是最短路徑。考慮從i到j的一條最短路徑p,假定p最多包含m條邊,假定沒有權值為負值的環路,且m為有限值。如果i=j,則p的權重為0且不包含任何邊。如果i和j不同,則將p分解為,其中路徑p’最多包含m-1條邊,所以δ(i, j) =δ(i, k)+。
設為從i到j的最多包含m條邊的任意路徑中的最小權重。當m=0時,從i到j之間存在一條沒有邊的最短路徑當且僅當i=j。所以:
對於m>0,有 =。
如果i到j之間最短路徑,則該路徑為簡單路徑,其中包含的邊最多為n-1,所以有:
對於所有的節點i和j,有 = (),所以, = W。下面的演算法假定已經知道了W和的情況下,給出如何計算,其中,L表示, L’表示,該演算法的時間複雜度為O():
現在可以看到上面的演算法與矩陣乘法的關係了。假定希望計算矩陣乘積C = A*B,對於i,j=1,2,...,n,有 = 。如果在 = 做出下面的替換:
就可以得到 = 。因此,如果對演算法EXTEND-SHORTEST-PATHS做出上面的替換,就可以得到標準的矩陣乘法的演算法。
如前所述,矩陣包含的是最短路徑權重,所以,下面的演算法可以在O()時間內,計算出該矩陣陣列:
我們的目標並不是要計算所有的矩陣,我們感興趣的僅僅是矩陣。因為有:正如傳統的矩陣乘法是相關的,所以由EXTEND-SHORTEST-PATHS過程所定義的演算法也是相關的。所以可以採用重複平方的技術計算該矩陣序列,該演算法的時間複雜度可以減少為O();
二:Floyd-Warshall演算法
Floyd-Warshall演算法採用不同的動態規劃公式解決所有節點對的最短路徑問題,它的執行時間是O(),該演算法同樣假設:可以存在負權重的邊,但不能存在權重為負值的環路。
Floyd-Warshall演算法考慮一條最短路徑上的中間節點,這裡簡單路徑p=<>上的中間節點指的是路徑p上除和之外的任意結點。
假定圖G的所有節點V={1,2,...,n},考慮其中的子集{1,2,...,k}。對於任意的結點i,j∈V,考慮從i到j的所有中間節點均取自集合{1,2,...,k}的路徑。並設p為其中的最短路徑,分兩種情況討論:
a:如果結點k不是p上的中間節點,則路徑p上的所有中間節點都屬於集合{1,2,...,k-1}。因此,從i到j的中間節點均取自集合{1,2,...,k}的一條最短路徑,同樣也是從i到j的中間節點均取自集合{1,2,...,k-1}的一條最短路徑。
b:如果結點k是路徑p上的中間節點,則p可以分解為,所以,p1上的所有中間節點都屬於集合{1,2,...,k-1},同理p2也是。
根據上面的觀察,設為從i到j的所有中間節點全部取自集合{1,2,...,k}的一條最短路徑的權重。當k=0時,i到j的路徑沒有中間節點,這樣的路徑最多隻有一條邊,所以有 = 。根據上面的討論,可以有:
因為對於所有的路徑,所有的中間節點都屬於集合{1,2,...,n},矩陣=給出的就是最終的矩陣: =δ(i, j)。演算法如下,該演算法的執行時間為O():
另外,可以在計算的同時計算前驅矩陣,具體來說,需要計算一個矩陣序列:,這裡 =,並且定義為從i到j的一條所有中間節點都取自集合{1,2,...,k}的最短路徑上,j的前驅結點。
所以,可以給出的一個遞迴公式,當k=0時,從i到j的一條最短路徑上沒有中間節點,所以:
如果k>1,則有:
,這樣,就可以在計算的同時,計算前驅矩陣了,下面是一個運算過程:
給定有向圖G=(V, E),結點集合V={1,2,..., n},希望判斷對於所有的i和j,圖G中是否包含一條從節點i到j的路徑,這稱為圖G的傳遞閉包問題。
一種計算圖G的傳遞閉包的辦法是給E中的每條邊賦予權重1,然後執行Floyd-Warshall演算法,如果存在一條從i到j的路徑,則有< n;否則,。這種演算法的時間複雜度為O()。
可以有另外一種演算法,該演算法使用邏輯或操作和邏輯與操作替換Floyd-Warshall演算法中的算術操作min和+。對於i,j,k=1,2,...,n,定義:如果圖G中存在一條從節點i到結點j的所有中間節點都取自集合{1,2,...,k}的路徑,則 = 1,否則, = 0。所以,當k=0時,有:
,對於k>=1,有:
= ,所以演算法如下:
該演算法從結構上類似於Floyd-Warshall演算法,執行時間為O(),但是邏輯運算通常要比算術運算要快,而且TRANSITIVE-CLOSURE所需要的空間更少。
三:用於稀疏圖的johnson演算法
johnson演算法可以在O()時間內找到所有節點對之間的最短路徑。對於稀疏圖來說,演算法在漸近意義上要好於矩陣的重複平方法或Floyd-Warshall演算法。演算法要麼返回一個包含所有節點對的最短路徑權重的矩陣,要麼報告輸人圖中存在一個負權值的迴路。演算法需要使用Dijkstra演算法和Bellman-Ford演算法作為其子程式。
Johnson演算法使用的技術稱為重新賦予權重。如果圖G=(V, E)中所有的邊權重w皆為非負值,則可以採用對每個節點執行Dijkstra演算法找到所有節點對的最短路徑,如果該圖包含權重為負值的邊,但沒有權重為負值的環路,則只要計算出一組新的非負權重值,然後使用同樣的方法即可。新賦予的權重w’必須滿足下面的性質:
a:多於所有頂點對u、v∈V,一條路徑p是利用加權函式w時從u到v的一條最短路徑,當且僅當p也是利用加權函式w’時從u到v的一條最短路徑。
b:對於所有的邊(u, v),新的權重w’(u, v)是非負值。
給定帶權重的有向圖G=(V, E),其權重函式為w,設h: v->R為任意函式,該函式將節點對映到實數上。對於每條邊(u,v),定義w’(u,v)= w(u, v) + h(u) – h(v)。設p = <>為從節點到節點的任意一條路徑,那麼p是在使用權重函式w時從節點到節點的一條最短路徑,當且僅當p是在使用權重函式w’時從節點到節點的一條最短路徑。即w(p) = δ()當且僅當w’(p) =δ'()。而且,圖G在使用權重函式w時不包含負值環路,當且僅當G在使用權重函式w’時不包含負值環路。
下一個目標是確保第二個屬性成立,也就是所有邊(u, v),w’(u,v)>=0。如果給定圖G=(V, E),製作一幅新圖G’ = (V’, E’)。其中V’ = V∪{s},s是一個新節點。E’ = E∪ {(s,v): v∈V},並且,對於所有節點v∈V, w(s, v) = 0。所以G’不包含權重為負值的環路當且僅當圖G不包含權重為負值的環路。現在定義函式h,對於所有節點v∈V’,h(v) =(s)。所以w’(u, v) = w(u, v)+ h(u) – h(v)。根據三角不等式定理,可以得到w’(u, v)>=0。
Johnson演算法執行過程中需要使用Bellman-ford演算法和Dijkstra演算法。該演算法假定所有的邊都儲存在鄰接連結串列裡,返回一個|V|*|V|的矩陣D = ,其中 =δ(i, j)。
如果使用斐波那契堆來實現Dijkstra演算法,則Johnson演算法的執行時間為O(),使用更簡單的二叉堆實現,則時間為O(VE lg V),在稀疏圖的情況下,仍然比Floyd-warshall演算法快。