上一週去了一趟說走就走的治療之旅,所以算法課都沒能上。:( 不過,人生有過這樣一次,很足夠。只要永遠做自己認爲對的事情就不會有跨不過去的坎。
跟上週一樣,這一週的內容包含幾個小部分,分別爲最短路徑動態規劃、所有點對之間的最短路徑和網絡流。
第一部分:最短路徑動態規劃
對於一個有向圖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則爲一個最大流。