ISAP 演算法的學習

2021-06-22 20:22:24 字數 3181 閱讀 2549

演算法與數學

網路流-最大流問題 isap 演算法解釋

內容提要 [隱藏]

1 約定

2 引入

3 演算法解釋

4 實現

isap 是圖論求最大流的演算法之一,它很好的平衡了執行時間和程式複雜度之間的關係,因此非常常用。

約定我們使用鄰接表來表示圖,表示方法可以見文章帶權最短路 dijkstra, spfa, bellman-ford, asp, floyd-warshall 演算法分析或二分圖的最大匹配、完美匹配和匈牙利演算法的開頭(就不重複貼**了)。在下文中,圖的源點(source)表示為 s ,匯點(sink)表示為 t ,當前節點為 u 。建圖時,需要建立雙向邊(設反向的邊容量為0)才能保證演算法正確。

引入求解最大流問題的乙個比較容易想到的方法就是,每次在殘量網路(residual network)中任意尋找一條從 s 到 t 的路徑,然後增廣,直到不存在這樣的路徑為止。這就是一般增廣路演算法(labeling algorithm)。可以證明這種不加改進的貪婪演算法是正確的。假設最大流是 f ,那麼它的執行時間為 o( f⋅∣e∣) 。但是,這個執行時間並不好,因為它和最大流 f 有關。

人們發現,如果每次都沿著殘量網路中的最短增廣路增廣,則執行時間可以減為 o(∣e∣2⋅∣v∣) 。這就是最短增廣路演算法。而 isap 演算法則是最短增廣路演算法的乙個改進。其實,isap 的意思正是「改進的最短增廣路」 (improved shortest augmenting path)。

順便說一句,上面討論的所有演算法根本上都屬於增廣路方法(ford-fulkerson method)。和它對應的就是大名鼎鼎的預流推進方法(preflow-push method)。其中最高標號預流推進演算法(highest-label preflow-push algorithm)的複雜度可以達到 o(∣v∣2∣e∣−−−√) 。雖然在複雜度上比增廣路方法進步很多,但是預流推進演算法複雜度的上界是比較緊的,因此有時差距並不會很大。

演算法解釋

概括地說,isap 演算法就是不停地找最短增廣路,找到之後增廣;如果遇到死路就 retreat,直到發現 s, t 不連通,演算法結束。找最短路本質上就是無權最短路徑問題,因此採用 bfs 的思想。具體來說,使用乙個陣列 d ,記錄每個節點到匯點 t 的最短距離。搜尋的時候,只沿著滿足 d[u]=d[v]+1 的邊 u→v (這樣的邊稱為允許弧)走。顯然,這樣走出來的一定是最短路。

原圖存在兩種子圖,乙個是殘量網路,乙個是允許弧組成的圖。殘量網路保證可增廣,允許弧保證最短路(時間界較優)。所以,在尋找增廣路的過程中,一直是在殘量網路中沿著允許弧尋找。因此,允許弧應該是屬於殘量網路的,而非原圖的。換句話說,我們沿著允許弧,走的是殘量網路(而非原圖)中的最短路徑。當我們找到沿著殘量網路找到一條增廣路,增廣後,殘量網路肯定會變化(至少少了一條邊),因此決定允許弧的 d 陣列要進行相應的更新(順便提一句,dinic 的做法就是每次增廣都重新計算 d 陣列)。然而,isap 「改進」的地方之一就是,其實沒有必要馬上更新 d 陣列。這是因為,去掉一條邊只可能令路徑變得更長,而如果增廣之前的殘量網路存在另一條最短路,並且在增廣後的殘量網路中仍存在,那麼這條路徑毫無疑問是最短的。所以,isap 的做法是繼續增廣,直到遇到死路,才執行 retreat 操作。

講到這裡,isap 演算法的框架內容就講完了。對於**本身,還有幾個優化和實現的技巧需要說明。

演算法執行之前需要用 bfs 初始化 d 陣列,方法是從 t 到 s 逆向進行。

演算法主體需要維護乙個「當前節點」 u ,執行這個節點的前進、retreat 等操作。

記錄路徑的方法非常簡單,宣告乙個陣列 p ,令 p[i] 等於增廣路上到達節點 i 的邊的序號(這樣就可以找到從哪個頂點到的頂點 i )。需要路徑的時候反向追蹤一下就可以了。

判斷殘量網路中 s, t 不連通的條件,就是 d[s]≥∣v∣ 。這是因為當 s, t 不連通時,最終殘量網路中 s 將沒有任何鄰接點,對 s 的 retreat 將導致上面條件的成立。

gap 優化。gap 優化可以提前結束程式,很多時候提速非常明顯(高達 100 倍以上)。gap 優化是說,進入 retreat 環節後, u, t 之間的連通性消失,但如果 u 是最後乙個和 t 距離 d[u] (更新前)的點,說明此時 s, t 也不連通了。這是因為,雖然 u, t 已經不連通,但畢竟我們走的是最短路,其他點此時到 t 的距離一定大於 d[u] (更新前),因此其他點要到 t ,必然要經過乙個和 t 距離為 d[u] (更新前)的點。gap 優化的實現非常簡單,用乙個陣列記錄並在適當的時候判斷、跳出迴圈就可以了。

另乙個優化,就是用乙個陣列儲存乙個點已經嘗試過了哪個鄰接邊。尋找增廣的過程實際上類似於乙個 bfs 過程,因此之前處理過的鄰接邊是不需要重新處理的(殘量網路中的邊只會越來越少)。具體實現方法直接看**就可以,非常容易理解。需要注意的一點是,下次應該從上次處理到的鄰接邊繼續處理,而非從上次處理到的鄰接邊的下一條開始。

最後說一下增廣過程。增廣過程非常簡單,尋找增廣路成功(當前節點處理到 t )後,沿著你記錄的路徑走一遍,記錄一路上的最小殘量,然後從 s 到 t 更新流量即可

int source; // 源點

int sink; // 匯點

int p[max_nodes]; // 可增廣路上的上一條弧的編號

int num[max_nodes]; // 和 t 的最短距離等於 i 的節點數量

int cur[max_nodes]; // 當前弧下標

int d[max_nodes]; // 殘量網路中節點 i 到匯點 t 的最短距離

bool visited[max_nodes];

// 預處理, 反向 bfs 構造 d 陣列

bool bfs()}}

return visited[source];

}// 增廣

int augment()

u = sink;

// 從匯點到源點更新流量

while (u != source)

return df;

}int max_flow()

bool advanced = false;

for (int i = cur[u]; i < g[u].size(); i++)

}if (!advanced)

}return flow;

}

網路流 最大流問題 ISAP 演算法解釋

august 7,2013 程式設計指南 isap 是圖論求最大流的演算法之一,它很好的平衡了執行時間和程式複雜度之間的關係,因此非常常用。我們使用鄰接表來表示圖,表示方法可以見文章帶權最短路 dijkstra,spfa,bellman ford,asp,floyd warshall 演算法分析或二...

網路最大流 ISAP演算法詳解與模板

isap演算法 isap improved shortest augumenting path 演算法是改進版的sap演算法,如果對效率要求很高的時候,可以用該演算法。1 概述 演算法基於這樣的乙個事實 每次增廣之後,任意結點到匯點 在殘餘網路中 的最短距離都不會減小。這樣,我們可以利用d i 表示...

poj 3469 isap演算法求最大流

include include define debug ifdef debug define debug printf va args else define debug endif define n 20010 define m 1800000 define max int 0x3fffffff...