網絡流(network-flows)是一種類比水流的解決問題方法,與線性規劃密切相關。網絡流的理論和應用在不斷髮展。而咱們今天要講的就是網絡流裏的一種常見問題——最大流問題。node
最大流問題(maximum flow problem),一種組合最優化問題,就是要討論如何充分利用裝置的能力,使得運輸的流量最大,以取得最好的效果。求最大流的標號算法最先由福特和福克遜與與1956年提出,20世紀50年代福特(Ford)、(Fulkerson)創建的「網絡流理論」,是網絡應用的重要組成成分。c++
再解決這個問題前,咱們要先弄懂一些定義:算法
網絡流圖是一張只有一個源點和匯點的有向圖,而最大流就是求源點到匯點間的最大水流量,下圖的問題就是一個最基本,經典的最大流問題網絡
對於弧(u,v)來講,流量就是其上流過的水量(咱們一般用f(u,v)表示),而容量就是其上可流過的最大水量(咱們一般用c(u,v)表示),只要知足f(u,v)<=c(u,v),咱們就稱流量f(u,v)是可行流(對於最大流問題而言,全部管道上的流量必須都是可行流)。優化
若是一條路上的全部邊均知足:spa
正向邊: f(u,v)< c(u,v) ——– 反向邊:f(u,v)> 03d
假若有這麼一條路,這條路從源點開始一直一段一段的連到了匯點,而且,這條路上的每一段都知足流量<容量,注意,是嚴格的<,而不是<=。那麼,咱們必定能找到這條路上的每一段的(容量-流量)的值當中的最小值delta。咱們把這條路上每一段的流量都加上這個delta,必定能夠保證這個流依然是可行流。這樣咱們就獲得了一個更大的流,他的流量是以前的流量+delta,而這條路就叫作增廣路. From 網絡流(Network Flow)code
則咱們稱這條路徑爲一條增廣路徑,簡稱增廣路。blog
好了,弄懂了一些定義,接下來就能夠介紹著名的Ford-Fulkerson算法了。get
如圖所示,若是咱們每次都找出一條增廣路,只要這條增廣路通過匯點,那說明此時水流還能夠增長,增長的量爲d(d=min(d,c(u,v)-f(u,v))或d=min(d,f(u,v)))。
咱們能夠這樣理解:對於每一條正向邊,他能添加的最大水流爲c(u,v)-f(u,v)。而對於反向邊來講,當正向邊上的水流增多時,反向邊自身的反向水流會減小,而其能減小的最多水量爲f(u,v)。因爲要保證添加水流以後,全部的f(u,v)都是可行流,因此咱們取最小值。
增長以後,咱們要更新流量,每條正向邊+d,每條反向邊-d便可。
既然這樣,咱們的思路就是:
1.找出一條增廣路徑 ——2.修改其上點的值——3.繼續重複1,直至找不出增廣路。則此時源點的匯出量即爲所求的最大流。
那麼上代碼:
#include<bits/stdc++.h> #include<vector> #define maxn 1200 #define INF 2e9 using namespace std; int i,j,k,n,m,h,t,tot,ans,st,en; struct node{ int c,f; }edge[maxn][maxn]; int flag[maxn],pre[maxn],alpha[maxn],q[maxn],v; int read(){ char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0'; while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x; } void bfs(){ memset(flag,0xff,sizeof(flag));memset(pre,0xff,sizeof(pre));memset(alpha,0xff,sizeof(alpha)); flag[st]=0;pre[st]=0;alpha[st]=INF;h=0,t=1;q[t]=st; while(h<t){ h++;v=q[h]; for(int i=1;i<=n;i++){ if(flag[i]==-1){ if(edge[v][i].c<INF&&edge[v][i].f<edge[v][i].c){ flag[i]=0;pre[i]=v;alpha[i]=min(alpha[v],edge[v][i].c-edge[v][i].f);q[++t]=i; } else if(edge[i][v].c<INF&&edge[i][v].f>0){ flag[i]=0;pre[i]=-v;alpha[i]=min(alpha[v],edge[i][v].f);q[++t]=i; } } } flag[v]=1; } } void Ford_Fulkerson(){ while(1){ bfs(); if(alpha[en]==0||flag[en]==-1){ break; } int k1=en,k2=abs(pre[k1]);int a=alpha[en]; while(1){ if(edge[k2][k1].c<INF) edge[k2][k1].f+=a; else if(edge[k1][k2].c<INF) edge[k1][k2].f-=a; if(k2==st) break; k1=k2;k2=abs(pre[k1]); } alpha[en]=0; } } void flow(){ int maxflow=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(i==st&&edge[i][j].f<INF) maxflow+=edge[i][j].f; } printf("%d",maxflow); } int main(){ int u,v,c,f; n=read();m=read();st=read();en=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) edge[i][j].c=INF,edge[i][j].f=0; for(int i=1;i<=m;i++){ u=read();v=read();c=read(); edge[u][v].c=c; } Ford_Fulkerson(); flow(); return 0; }