網路流演算法(Network Flow)
網路流概覽
1.網路流(Network Flow)概念
網路流起源於對於交通網路的分析,舉一個非正式的例子,網路流演算法的目的就是找到帶權有向圖中從源點到匯點的traffic的大小。我們的目標是在多項式時間內解決問題。
我們一般要求的是最大流,如果把源點比作工廠的話,問題就是求從工廠最大可以發出多少貨物,是不至於超過道路的容量限制,也就是——最大流。
2.網路流的一些定義
流量網路:給一個有向圖
源點:圖中有n個點,有m條有向邊,有一個點
匯點:另一個點
容量和流量:在圖中的每條有向邊上有兩個量,容量
舉個例子:通常可以把這些邊想象成道路,流量就是這條道路的車流量,容量就是道路可承受的最大的車流量。很顯然的,流量<=容量。而對於每個不是源點和匯點的點來說,可以類比的想象成沒有儲存功能的貨物的中轉站,所有“進入”他們的流量和等於所有從他本身“出去”的流量。
1.容量限制(Capacity conditions):對於每條邊
2.平衡限制(Conservation conditions):對於每一個非
value of a flow:從源點
從源點s出發的可以有多條邊,這裡指的是整個圖的總流量。
最大流:如果把源點比作工廠的話,最大流問題就是求從工廠最大可以發出多少貨物,是不至於超過道路的容量限制。Flow Network中的Maximum Flow value,這就是最大流的定義。
Residual graph: 由圖 G中的流派生而來,記作
-
-
- Forward edges: if
- **Backward edges:**if e has positive flow
augmenting path: 是一條在剩餘圖
• The bottleneck of a path
is the minimum residual capacity of all edges in that path
• To augment flow f using path P consists of modifying the flow in all edges of P as follows:
◮ let
◮ increase the flow by b in all forward edges of P
◮ decrease the flow by b in all backward edges of P
3.
4.
動態規劃的經典問題
1.加權間隔排程
輸入:一組n個間隔,沒個時間段有開始時間、結束時間以及時間段的權重。
輸出:不互相重疊的一組具有最大權重的間隔集。
Eg:
解決方法:
通過“帶記憶”的儲存加遞迴的方式解決。
int Memoized Opt(j)
if j = 0 then return(0)
else
if M[j] = "undefined" then
M[j] ← max v(j) + Opt(p(j)), Opt(j − 1)
return M[j]
將間隔按照結束時間排序,第j個間隔時的權重和應該為:j的權重與上一個不與第j個間隔重合的間隔的Opt(p(j))的和;與Opt(j-1)相等。當中最大的一個。
也可以自底向上的用遞推的方式計算
IterativeComputeOpt
M[0] ← 0
for j ← 1 to n do
M [j] ← max v(j) + M [p(j)], M [j − 1]
2.分段最小二乘問題
給出一組n個點,需要確定一條能夠最好的擬合(fit)這些點的直線。有error = 點到直線的距離的平方,而這條直線具有最小的error。
使用多條直線能夠做到更好的擬合,但是分成越多的段對於我們的資料分析沒有意義。因為有指數中不同的劃分(相當於求子集),使用暴力搜尋是不現實的。
解決方法:
我們引入一個可變的變數C,作為演算法的懲罰值,擬合劃分的線越多,C值越大。因此我們的目標就是找到最小的:C + 各條線的error值。
定義e(i,j) 是擬合pi到pj這些點時的error;OPT(i)為pi到pj的最優解(OPT(0) = 0)。此時可知:
我們無法確定i的值,但是可以選擇能夠給出最小值的i的值。
由此我們可以得到虛擬碼:
計算每個點的分段最小二乘法的error值,然後儲存在陣列中,之後遍歷陣列來獲得最好的擬合線。
SegmentedLeastSquares(n)
Array M[0...n]
M[0] ← 0
for all pairs (i, j)
compute least squares error[i, j] for segment pi . . . pj
for j ← 1 to n
M [j ] ← min1≤i≤j (error[i, j ] + C + M [i − 1] )
Find Segments(j)
find i that minimizes error[i,j]+C+M[i−1]
if i > 1 then Find Segments(i − 1)
output the best fit line for segment pi...pj
3.汽車裝載問題
要求儘可能多的向汽車上裝載貨物。
輸入:n個箱子,每一個箱子i有重量wi;汽車的總承重量為W。
輸出:在滿足總重量限制下,所能儘可能多的裝載重量的箱子的子集。
解決方法:
很明顯,在這種情況下,貪心演算法並不能給出最優解。比如汽車總承重量為10,有4個箱子,分別重量為8、3、3、3。最優解為9,但貪心只會選擇一個重量為8的箱子。
我們可以通過減少箱子數量和減少總重量限制來將問題化解為更小的問題。我麼用OPT(i, w)表示我們在重量限制為w條件下,在前i個箱子中所能裝載的最大重量。
對於第i個箱子,我們可以選擇裝載它或者不裝載它,則有:
應注意,wi不能大於w,否則只能選擇不裝載箱子i。此演算法有時間複雜度:O(n·W)。
4.揹包問題(Knapsack Problem)
輸入:n件物品,物品i有重量wi和價值vi;揹包總重量W。
輸出:一組在滿足總重量限制下的具有最大價值的物品集合。
解決方法:
此時貪心也無法得到最優解,例如W = 100,有兩個物品,重量與價值分別為(20, 80)、(90, 90),此時貪心會選擇最小重量,但是揹包已經裝不下了。
揹包問題就像是引入了價值的卡車裝載問題。令OPT(i, w)表示在前i個物品中,在w重量限制下,所能取得的最大價值。我們可以選擇要不要這件物品,則有:
應注意,wi不能大於w,否則只能選擇不裝載物品i。此演算法有時間複雜度:O(n·W)。
4.序列對比(Sequence Alignment)
為了確定兩個序列之間的相似性,將兩個string按照一定的規律排列。序列中可以通過插入間隔來獲得更好的相似性,但我們會為gap和mismatch分配不同的懲罰值,gap是有cost的。給出兩個string,計算它們之間的相似程度
解決方法:
設兩個string為x和y,我們令A(i, j)表示對於x1到xi,y1到yj的最佳匹配值,即最小的gap與mismatch懲罰值。則有:
虛擬碼:
ALIGN( X[1:m],Y[1:n] )
for j ← 0 to n
A[0,j] ← jδ
for i ← 1 to m
A[i, 0] ← iδ
for j ← 1 to n
A[i,j]←min{αxi,yj +A[i−1,j−1], δ+A[i−1,j],
δ+A[i,j−1] }
5.帶負邊的最短路徑(Bellman-Ford Shorest Path Algorithm)
輸入:帶權有向圖G,c(v, w)表示從頂點v到w的邊的cost,可以為負。
輸出:一個負環(所有邊的cost之和為負)或者一條從s到t的最短路徑。
實際生活中,比如經濟學中的互相轉賬就有可能會引入負邊,然而Dijkstra演算法因此受限,無法解決。這時就應當使用Bellman-Ford Shortest Path Alg,使用前我們需要知道一條定理:如果有向圖沒有負環,那麼對於有n個點的圖G,從點s到t的最短路徑至多含有n-1條邊。
解決方法:
令OPT(i, v)表示在小於等於i條邊的情況下,從點v到點t的最小path cost。
我們要求的是OPT(n - 1, s),有遞迴初始條件OPT(0, t) = 0,OPT(0, v) = +∞(v !=
t)。則有:
虛擬碼:
Shortest-Path(G, s, t)
n ← number of nodes in G
for all v except t, initialize M[v] ← +∞
M[t] ← 0
for i←1 to n−1
for all e=(v,w)∈E(G)
M [v] ← min(M [v], c(v, w) + M [w])
return M[s]
可以通過在計算OPT(i, v),只取存在邊(v, w)的點,來將時間複雜度降低到O(m·n)。