\(原題戳這裏\)
>最大流最小割定理$(Maximum Flow, Minimum Cut Theorem): $c++網絡的最大流等於最小割
具體的證實分三部分
1.任意一個流都小於等於任意一個割 這個很好理解 自來水公司隨便給你家通點水 構成一個流 恐怖分子隨便砍幾刀 砍出一個割 因爲容量限制 每一根的被砍的水管子流出的水流量都小於管子的容量 每一根被砍的水管的水原本都要到你家的 如今流到外面 加起來獲得的流量仍是等於原來的流 管子的容量加起來就是割 因此流小於等於割 因爲上面的流和割都是任意構造的 因此任意一個流小於任意一個割
2.構造出一個流等於一個割 當達到最大流時 根據增廣路定理 殘留網絡中s到t已經沒有通路了 不然還能繼續增廣 咱們把s能到的的點集設爲S 不能到的點集爲T 構造出一個割集\(C[S,T] S\)到T的邊必然滿流 不然就能繼續增廣 這些滿流邊的流量和就是當前的流即最大流
把這些滿流邊做爲割 就構造出了一個和最大流相等的割
3.最大流等於最小割 設相等的流和割分別爲Fm和Cm 則由於任意一個流小於等於任意一個割 任意\(F≤Fm=Cm≤任意C\) 定理說明完成,證實以下: 對於一個網絡流圖\(G=(V,E)\),其中有源點s和匯點t,那麼下面三個條件是等價的:git
- 流f是圖G的最大流
- 殘留網絡Gf不存在增廣路
- 對於G的某一個割\((S,T)\),此時\(f = C(S,T)\) 首先證實\(1 => 2\):
咱們利用反證法,假設流f是圖G的最大流,可是殘留網絡中還存在有增廣路\(p\),其流量爲\(fp\)。則咱們有流\(f’=f+fp>f\)。這與\(f\)是最大流產生矛盾。
接着證實\(2 => 3\):網絡
假設殘留網絡\(Gf\)不存在增廣路,因此在殘留網絡\(Gf\)中不存在路徑從s到達t。咱們定義S集合爲:當前殘留網絡中s可以到達的點。同時定義\(T=V-S\)。
此時\((S,T)\)構成一個割\((S,T)\)。且對於任意的\(u∈S,v∈T\),有\(f(u,v)=c(u,v)\)。若\(f(u,v) < c(u,v)\),則有\(Gf(u,v) > 0\),s能夠到達v,與v屬於T矛盾。
所以有\(f(S,T)=Σf(u,v)=Σc(u,v)=C(S,T)\)。 最後證實\(3 => 1\):spa
因爲f的上界爲最小割,當f到達割的容量時,顯然就已經到達最大值,所以f爲最大流。 這樣就說明了爲何找不到增廣路時,所求得的必定是最大流。
源點:只有流出去的點
匯點:只有流進來的點
流量:一條邊上流過的流量
容量:一條邊上可供流過的最大流量
殘量:一條邊上的容量-流量
EK時間複雜度:\(O(n m^2)\)code
#include <bits/stdc++.h> using namespace std; typedef long long LL ; inline LL In() { LL res(0),f(1); register char c = getchar() ; while(!isdigit(c)) { if(c == '-') f = -1 ; c = getchar() ; } while(isdigit(c)) res = (res << 1) + (res << 3) + (c & 15) , c = getchar() ; return res * f ; } const int INF = 0x3f3f3f3f ; const int N = 1000000 + 5 ; int n , m , s , t ; int cnt = 1 ; int cost[N] ; int from[N] ; int to[N] ; int nxt[N] ; int head[N] ; int dis[N] ; int vis[N] ; int flow[N] ; int last[N] ; int maxflow ; queue <int> q ; inline void Add(int x,int y,int z) { cost[++cnt] = z ; from[cnt] = x ; to[cnt] = y ; nxt[cnt] = head[x] ; head[x] = cnt ; } inline bool bfs(int s,int y) { for(register int i = 1 ; i <= n ; i ++) last[i] = 0 , vis[i] = -1 ; q.push(s) , dis[s] = 0 , vis[s] = 1 , flow[s] = INF ; while(!q.empty()) { int u = q.front() ; q.pop() ; vis[u] = 0 ; for(register int i = head[u] ; i != -1 ; i = nxt[i]) { int v = to[i]; if(cost[i] and vis[v] == -1) { flow[v] = min (flow[u] , cost[i]) ; last[v] = i ; q.push(v) ; vis[v] = u ; } } } if(vis[t] != -1) return 1; return 0 ; } inline void update(int s,int t) { int now = t ; while(now != s) { int i = last[now] ; cost[i] -= flow[t] ; cost[i^1] += flow[t] ; now = from[i] ; } maxflow += flow[t] ; } inline void EK() { maxflow = 0 ; while(bfs(s,t) == 1) update(s,t) ; } signed main() { n = In() ; m = In() ; s = In() ; t = In() ; memset(head,-1,sizeof(head)) ; for(register int i = 1 ; i <= m ; i ++) { int x = In() ; int y = In() ; int z = In() ; Add(x,y,z) ; Add(y,x,0) ; } EK() ; cout << maxflow << endl ; return 0; }