算法課筆記系列(六)—— 圖(Part2)

上一週去了一趟說走就走的治療之旅,所以算法課都沒能上。:( 不過,人生有過這樣一次,很足夠。只要永遠做自己認爲對的事情就不會有跨不過去的坎。

跟上週一樣,這一週的內容包含幾個小部分,分別爲最短路徑動態規劃、所有點對之間的最短路徑和網絡流。

第一部分:最短路徑動態規劃

對於一個有向圖G=(V, E), 每一條邊權重爲cvw(權重可爲負), 問題是找到從節點s到t的最短的路徑。如果邊的權重中有負值,則Dijkstra方法不適用。因此我們想到一個辦法,給每一個權值加上一個正常數使得每一條邊的權重都爲非負,這個方法也不行。

這裏定義一個負(成本)環。如下圖所示,顧名思義,所有邊的權值的和爲負數。

                                  

如果一個從s到t的路徑中包含一個負(成本)環,那s-t之間不存在最短路徑,否則,存在一個最短路徑。如下圖。

                             

下面用動態規劃來解決最短路徑的問題。

定義OPT(i, v) 表示使用最多i條邊的最短的v到t的路徑P。

1) P中使用最多i-1條邊

OPT(i, v) = OPT(i - 1, v)

2) P使用第i條邊

如果(v, w)是第一條邊,那麼OPT使用(v, w), 然後選擇最佳的w-t路徑使用最多i-1條邊

          

通過之前的觀察,可以得出,如果沒有負環,那麼OPT(n - 1, v)爲最短的v-t路徑的長度。

實現代碼如下:

          

時間複雜度爲O(mn), 空間複雜度爲O(n^2).

下面提出一種改進。

保持一個矩陣M[v]爲我們目前能夠找到的最短的v-t路徑。除非M[v]在前一個迭代中改變了,否則不需要檢查(v, w)形成的邊。這裏有這樣一個定理,在整個算法中,M[v]是v-t路徑的長度,在i輪更新之後,M[v]不會大於使用不多於i條邊的最短路徑的長度。內存消耗爲O(m+n),時間複雜度爲O(mn)最壞情況,但是實際會更快。

Bellman-Ford實現算法如下:

          

使用以上算法可以證明,如果對於所有的v有OPT(n, v) = OPT(n - 1, v),那麼就沒有負環。

如果OPT(n, v) < OPT(n - 1, v), 那麼任何從v到t的最短路徑都包含一個環W,並且,W包含負數的權值邊。

以上兩條可以用於檢測負環。Bellman-Ford算法的時間複雜度爲O(mn), 空間複雜度爲O(m+n).


第二部分:所有點對之間的最短路徑

最短路徑包含單源最短路徑問題和所有點對之間的最短路徑問題。單源最短路徑問題包含非負邊權重的Dijkstra算法(O(E+VlogV)),一般算法Bellman-Ford算法(O(VE)) 和 DAG算法一種Bellman-Ford的變化(O(V+E))。所有點對之間的最短路徑問題則包括,Dijkstra算法|V|次:O(VE+V2lgV), 和一般方法(下面要介紹的三種算法)。

給出一個圖G=(V, E), |V| = n, 邊和權重之間的函數關係爲w: E→R. 輸出爲最短路徑長度的nxn的矩陣,對於所有的i, j ∈V。

考慮在每一個頂點運行一次Bellman-Ford算法,時間爲O(V2E)

 

動態規劃

考慮一個有向圖nxn的鄰接矩陣,定義爲從i到j使用最多m條邊的一個最短路徑的權重。因爲我們得到

                

對於任意m = 1,2,…,n-1,

                

要證明以上式子,可以對進行條件鬆弛,對於任意的k從1到n,如果,那麼就將dij更新爲

沒有負環就意味着,

            

 以下爲所有點對之間的一般情況的三種算法:

1. 矩陣乘法

計算C=A · B, 其中C,A和B都爲nxn的矩陣,

             

使用傳統的算法需要O(n^3)的時間複雜度。

如果我們將+ 映射爲min,將·映射爲+, 那麼有

            

這樣,

           

單位矩陣I表示爲

            

(min,+)乘法是關聯的,在實數中,它形成了一種集合結構叫做閉合半環。因此,我們可以計算

            

得出,

            

時間複雜度爲,並不比n倍的Bellman-Ford算法好。

因此,一種改進的矩陣乘法算法是,不停平方,

 

這樣,只需要計算O(lgn)次的平方,

時間複雜度變爲

爲了檢測是否存在負權重環,需要檢查對角線是否含有負值需要額外的O(n)的時間。

 

2. Floyd-Warshall算法

該算法也是一個動態規劃,但是有着更快的速度。

定義是從i到j包含集合爲{1,2,…k}爲中間結點的最短路徑的權重

那麼有,,且,

尋找最段路徑的過程中會發生

                

循環爲

       

時間複雜度爲,並且更加有效。

3. Johnson算法

對每一個v∈V,給定一個標籤h(v),重新給每一條邊(u, v)∈E賦予權重

 

這樣,相同的兩個頂點之間的路徑將會被相同的值被重新賦權重。

A.找到一個標記爲h的頂點,使得對於所有的(u, v)∈E成立通過使用Bellman-Ford算法來解決差異限制

或者決定一個負權重環是否存在,所需時間爲O(VE).

B.對於每一個使用的頂點運行Dijsktra算法,時間複雜度

C.對每一個最短路徑長度重新賦權值產生原始圖的最短路徑長度,時間複雜度爲

因此,總的時間爲

 

第三部分 網絡流

最大流和最小切割是兩個非常常見的算法問題。

最小切割問題:

                

可以抽象爲通過邊的材料流動。

有向圖G=(V, E)沒有平行的邊,兩個不同的結點s爲source,t爲sink,c(e)是邊e的容量。

定義s-t切割是s∈A,t∈B的V的一個劃分(A,B)。cut (A,B)的容量是

因此,最小s-t劃分問題就是找到有着最小容量的一個s-t劃分。

流的問題則爲:

首先定義s-t流是一個滿足以下條件的函數:

對於每一條邊e∈E:;對於每一個頂點v∈V-{s,t},

流f的值定義爲,如下圖所示

                  

因此最大流問題就是找到s-t流的最大值。

流值定理爲:令f是任意的一個流,(A, B)是任意的s-t cut。那麼,通過cut傳送的網絡流等於總的離開s的量,即

 

以下爲一個形象的例子:

              

 

弱對偶性:令f是任意的一個流,(A, B)是任意的s-t cut。那麼,流的值最多爲cut的容量,即v(f) <= cap(A, B)

 

推論爲:如果v(f) = cap(A, B), 那麼f是最大的流,(A, B)是最小的cut

下面使用貪心算法來尋找一個最大流算法:

首先令所有的邊e∈E,都有f(e)=0. 找到一條s-t路徑P有每一條邊f(e) < c(e)。沿着路徑P分割流,重複該操作直到無法進行下去。這裏無法再進行下去的含義要注意,局部最優並不能夠推出全局最優。

                  

                 

              

 下面介紹一種剩餘圖,

                   

原始的邊爲e=(u, v)∈E,流f(e), 容量爲c(e). 剩餘容量定義爲

                  

則剩餘圖爲

剩餘邊有正的剩餘容量,因此,

Ford-Fulkerson算法可以用來找到最大流。也稱爲分割路徑算法。

                

           

分割路徑定理:如果不存在分割路徑算法,流f則爲一個最大流。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章