網路最大流Dinic
阿新 • • 發佈:2020-10-07
1.什麼是網路最大流
形象的來說,網路最大流其實就是這樣一個生活化的問題:現在有一個由許多水管組成的水流系統,每一根管道都有自己的最大通過水流限制(流量),
超過這個限制水管會爆(你麻麻就會來找你喝茶qwq)。現在,給定你一個出水口(原點),一個出水口(匯點),求這個網路中水流量的最大值。
????看起來很簡單對不對?在我們看起來的確是這樣的,而這部分的難點也確實不在思路上,而是在於演算法設計以及程式碼實現上。
2.怎麼求解網路最大流
首先想明白一件事情,對於一個節點來說,他接受的流量一定小於等於他給出的流量之和,否則,水管一定會爆掉。而對於一個節點來說,
他接受的流量有可能大於任意一個他出邊的流量,因為這個節點可以把接受流給出到不同的水管上,進而實現分流。
有了這兩點,思路就很清晰了(貪心算):
1.首先,我們需要尋找一條可行的流量方案(此時,不一定為最大流量)。
2.然後我們依次擴充套件這條路徑上的所有節點,看看這個節點是否還可以接受流量,直到已經滿流。
3.重複上述步驟,直到沒有可行流動路徑。
4.此時我們累加的流量即為網路最大流,我們把這種方法稱為最大流Dinic演算法
3.實現細節
這種演算法看起來簡單,實際上實現起來會遇到許多小毛病,以及許多很難理解的程式碼實現,這裡舉一個栗子
在步驟2的時候我們採用dfs進行擴充套件,也稱為網路最大流的擴充套件部分演算法,需要藉助到反邊這樣一個概念,即:兩個節點A,B間有一條權值為w無向邊
我們就把他拆分成一條由A指向B的有向邊與一條由B指向A的有向邊,其中,這兩條邊的權值之和為w,這樣一來一回,兩者相互抵消巧妙的實現了回溯
上程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define N 1000005 #define M 4*1000005 #define INF 0xfffffff using namespace std; int Read()//快讀 { int num=0,k=1; char c=getchar(); while(c!='-'&&(c<'0'||c>'9')) c=getchar(); if(c=='-') { k=-1; c=getchar(); } while(c<='9'&&c>='0') { num=(num<<3)+(num<<1)+c-'0'; c=getchar(); } return num*k; } struct node { int from; int to; int v; int next; }; node edge[2*M]; int cnt_edge=1,n,m,s,t; long long ans=0; int last[N],deep[N]; void add_edge(int u,int v,int w) { edge[++cnt_edge].from=u; edge[cnt_edge].to=v; edge[cnt_edge].v=w; edge[cnt_edge].next=last[u]; last[u]=cnt_edge; } bool bfs() //判斷是否有通路 { memset(deep,-1,sizeof(deep)); deep[s]=0; queue<int >q; q.push(s); while(!q.empty()) { int now=q.front(); q.pop(); for(int i=last[now];i;i=edge[i].next) { int j=edge[i].to; if(deep[j]==-1&&edge[i].v) { deep[j]=deep[now]+1; q.push(j); } } } return deep[t]!=-1; } int dfs(int now,int flow) //flow為當前流量 { if(now==t) return flow; int delta=flow; //delta是剩餘流量,就是流不下去的流量 for(int i=last[now];i;i=edge[i].next) { int to=edge[i].to; if((deep[to]==(deep[now]+1))&&edge[i].v > 0) { int d=dfs(to,min(delta,edge[i].v)); if(!d) deep[to] = 1e9; //剪枝優化,當前點無法下流 edge[i].v-=d;edge[i^1].v+=d;delta-=d;//流下去,反邊+d,方便迴流 if(!delta) break; } } return flow-delta; //返回這裡留下去了多少 ,即當前點的最大流量 } int main () { n=Read();m=Read();s=Read();t=Read(); int u,v,w; for(int i=1;i<=m;i++) { u=Read();v=Read();w=Read(); add_edge(u,v,w);add_edge(v,u,0); } while(bfs()) ans+=dfs(s,INF); printf("%lld\n",ans); return 0; }