網絡流初步詳解
眾所周知,網絡流是探究網絡上運輸的一種圖論分支。但是大多數人在第一次接觸這個題時都有些畏懼感(比如說我),大佬可以自信跳過..
本文包括:
1.網絡流的概念及基本性質
2.略談 Edmonds-Karp增廣路算法
3.詳談 Dinic 算法
4.網絡流的應用以及ISAP算法引入
1 . 網絡流的概念及基本性質
網絡流是圖論的一種重要分支,我們可以將網絡流初步理解為一種 水道 一樣的網絡。
基本定義: (部分參考《算法競賽進階指南》)
對於一個網絡 \(G = (V , E )\) 為一張有向圖,圖中的每條有向邊 $ ( X,Y)?E $ , 則 $ C(X,Y) = 0 $ 。圖中還有兩個節點 $ S , T $ 十分特殊,我們將其稱為 源點
我們將 \(f\) 函數稱作網絡的流函數。
對於 \((X,Y)∈E , f(X,Y)\) 稱為邊的流量 ,$ C(X,Y) - f(X,Y)$ 稱為邊的剩余流量。
知道大佬們都不想看, 那麽直接一點。
假設有一片有向的水域,有多條有向的河流,河流都從 \(S\) 點出發,最終都匯向 $ T$ 點。每條河流有一定的寬度,只允許最多不超過該條河流邊權值 的水流通過。
如上圖 ,藍點為源點 , 紅點為匯點。而紫色點和紫色邊顯然無用,選擇不流過紫色。
** 默認 S 點的水量有無限多。 **
在初步了解後,按照流函數的定義,一個網絡中的每條邊實際上都有一條反向邊,並且這些反向邊都有一個負的流量
基本性質:
1.容量限制
任意一條邊的流量必定小於它的容量(及它的邊權)。
2.斜對稱定理
一條邊\((X,Y)\)中 \(X\) 到 \(Y\) 的流量必定與其反邊\((Y,X)\)中 \(Y\) 到 \(X\) 的流量相反。
3.流量守恒定理
除了源點 $ S $ 和 匯點 $ T $外 ,任意節點的 流入總量 都等於 流出總量 。即不會存儲流量 。
2.略談 Edmonds-Karp增廣路算法
學習過匈牙利算法的同學已經了解增廣路的定義,沒有的話建議先 $ A$ 掉P3386 【模板】二分圖匹配
,將有利於理解本文(貌似沒有關聯)。
但是增廣路
一條增廣路從源點 \(S\) 到匯點 \(T\) 的路徑上各邊的剩余流量的最小值大於 0 。
而Edmonds-Karp增廣路算法(下列簡稱EK算法)的思路就是對該網絡進行BFS,不斷找出其增廣路,直至將該網絡上的所有增廣路全部找出。
EK算法的正確性顯然,在這裏就不給出詳細證明。(有興趣者可參考《算法競賽進階指南》)。
EK算法具體實現過程如下:
1 . 用BFS在網絡上尋找可行增廣路。
2 . 在BFS找到任意一條增廣路時計算出該增廣路上各邊剩余流量的最小值 min 。
3 . 最大流 \(maxflow\) 的值增加 min ,如此往復直至BFS找不增廣路。
給出圖 及 圖的最大流 7 作參考
代碼暫未上傳。
但是EK算法存在明顯的局限性,及每次更新都要從頭到尾BFS一下,只能解決 \(O(nm^2)\) 的網絡。
於是我們又有下面這個經一步優化的算法。
3.詳談 Dinic 算法
之所以詳談Dinic算法,是因為Dinic算法是代碼較簡單,較容易實現並且效率極高的網絡流算法之一,它對於普通的網絡圖,處理範圍可以達到 $ 10^4 - 10^5 $ 。而相比之下,EK算法僅有 $ 10^3 - 10^4 $的處理範圍。
並且某位大師推演出Dinic算法在二分圖中的復雜度僅有 $m \sqrt{n} $ , 所以可以在二分圖中愉快地跑網絡流 啦。上一道例題P1129 [ZJOI2007]矩陣遊戲,熟練後可以切了它。
我們先介紹一下Dinic算法的核心之一:殘量網。
殘量網是指在當前網絡中的所有節點以及 ** 剩余容量大於 \(0\) ** 的邊構成的子圖。
但是有了殘量網還不夠,要精準判斷殘量網上兩點 \(X,Y\) 的關系,即判斷它們是否有環之類神奇的邊,我們還要借助滿足 $d[y] = d[x] + 1 $ 的分層圖。
Dinic算法思路:
1 . 開一個隊列, 在殘量網中BFS一次,按照遍歷層數為每個點表上層次 $ d[ x ] $ ,構造分層圖並且判斷能否從源點 \(S\) 到達匯點 \(T\) 。如果失敗則說明殘量網無法到達匯點。
2 . 在構造好的殘量網上DFS尋找增廣路並且,更新邊及反邊,(否則DFS無法後悔)。
3 . 不斷重復 1 2 步驟直至構造的殘量網無法到達匯點。
實踐是檢驗真理的唯一標準
模板題P3376 【模板】網絡最大流
\(AC\)代碼及講解:
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3 , N = 10000 + 19 ;
int head[ N*2 ], d[ N ] , to[ N*10*2 ] , w[ N*10*2 ] , next[ N*10*2 ] ;
int n , m , s, t , tot = 1 , maxflow = 0 ;//maxflow記錄答案
inline int read()
{
int s = 0,w = 1;
char g = getchar();
while(g<'0'||g>'9'){if(g=='-')w*=-1;g = getchar();}
while(g>='0'&&g<='9'){s = s*10+g-'0';g = getchar();}
return s*w;
}
queue<int> q ;//廣搜時采用隊列
void add( int x , int y , int z ){
tot++; to[ tot ] = y , w[ tot ] = z , next[ tot ] = head[ x ] , head[ x ] = tot;
tot++; to[ tot ] = x , w[ tot ] = 0 , next[ tot ] = head[ y ] , head[ y ] = tot;
}//建立邊和反向邊,註意反向邊的流量初始為 0
bool bfs(){//在殘量網絡上構造分層圖
memset( d , 0 , sizeof(d) ) ; //將之前的分層清0,繼續跑殘量網絡找可行增廣路
while( q.size() ) q.pop() ; //隊列清 0 ;
q.push( s ) ; d[ s ] = 1 ; //將源點加入隊列,層數為 1 ,開始廣搜
while( q.size() ){
int x = q.front() ; q.pop() ;
for( int i = head[ x ] ; i ; i = next[ i ])
if( w[ i ] && !d[ to[i] ] ){//目標邊的流量不為0 且 為被遍歷分層
q.push( to[ i ] ) ;
d[ to [ i ] ] = d[ x ] + 1;
if( to[ i ] == t )return 1 ; //找到一條可行增廣路
}
}
return 0 ;//未找到,不存在增廣路
}
int dinic( int x , int flow ){ //在分層圖上進行增廣
if( x == t )return flow ;//源點即使匯點,流量不限量
int rest = flow , k ;
for( int i = head[ x ] ; i && rest ; i = next[ i ] )//當前可流入最大流量不為0 ,
if( w[ i ] && d[ to [ i ] ] == d[ x ] + 1 ){//目標路徑有剩余流量,且不存在環之類神奇的東西
k = dinic( to[ i ] , min( rest , w[ i ] ) );//繼續搜
if( !k )d[ to [ i ] ] = 0 ; //剪枝,如果 k(下一層可流入流量圖為 0 ),cut
w[ i ] -= k ;
w[ i ^ 1 ] += k ;//占用k流量,註意反邊要加上k,不然無法退回
rest -= k ; //當前節點的剩余匯入流量-k;
}
return flow - rest ; //遞歸完成
}
int main()
{
n = read() ; m = read() ; s = read() ; t = read() ;
for( int i = 1 ; i <= m ; ++i ){
int x = read() , y = read() , L = read() ;
add( x , y , L ) ;
}
int flow = 0 ;
while( bfs() ){//存在增廣路
while( flow = dinic ( s , inf ))maxflow += flow ;
}
printf("%d",maxflow) ;
return 0 ;
}
Dinic算法一定要手敲一遍板子,不然你連錯在哪都查不出來(除了機對)。
4.網絡流的應用以及ISAP算法引入
ISAP算法是EK算法的另一類優化, ISAP算法只需一次BFS即可,但代碼難度遠遠高於Dinic算法。
ISAP算法復雜度在非二分圖上高於Dinic算法,在二分圖則不如Dinic算法。
在此暫時不詳講,日後會更新ISAP算法詳解。
網絡流的應用
網絡流應用較廣, 但建議新手按以下順序A題,熟練算法和增強應用能力。
P3376 【模板】網絡最大流
U60438 及川奈砂的蛋糕
P1129 [ZJOI2007]矩陣遊戲
P2891 [USACO07OPEN]吃飯Dining
最後是網絡流24題
網絡流深入請見這位大佬:網絡流深入
本文到此結束,若有不足,懇請大佬指出。
如果你喜歡我的文章,請大力點贊支持!感謝。
網絡流初步詳解