日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

网络流的最大流入门(从普通算法到dinic优化)

發布時間:2024/10/8 编程问答 42 如意码农
生活随笔 收集整理的這篇文章主要介紹了 网络流的最大流入门(从普通算法到dinic优化) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網絡流(network-flows)是一種類比水流的解決問題方法,與線性規劃密切相關。網絡流的理論和應用在不斷發展。而我們今天要講的就是網絡流里的一種常見問題——最大流問題。

最大流問題(maximum flow problem),一種組合最優化問題,就是要討論如何充分利用裝置的能力,使得運輸的流量最大,以取得最好的效果。求最大流的標號算法最早由福特和福克遜與與1956年提出,20世紀50年代福特(Ford)、(Fulkerson)建立的“網絡流理論”,是網絡應用的重要組成成分。

再解決這個問題前,我們要先弄懂一些定義

網絡流圖是一張只有一個源點和匯點的有向圖,而最大流就是求源點到匯點間的最大水流量,下圖的問題就是一個最基本,經典的最大流問題

二.流量,容量和可行流

對于弧(u,v)來說,流量就是其上流過的水量(我們通常用f(u,v)表示),而容量就是其上可流過的最大水量(我們通常用c(u,v)表示),只要滿足f(u,v)<=c(u,v),我們就稱流量f(u,v)是可行流(對于最大流問題而言,所有管道上的流量必須都是可行流)。

三.增廣路

如果一條路上的所有邊均滿足:

正向邊: f(u,v)< c(u,v) ——– 反向邊:f(u,v)> 0

假如有這么一條路,這條路從源點開始一直一段一段的連到了匯點,并且,這條路上的每一段都滿足流量<容量,注意,是嚴格的<,而不是<=。那么,我們一定能找到這條路上的每一段的(容量-流量)的值當中的最小值delta。我們把這條路上每一段的流量都加上這個delta,一定可以保證這個流依然是可行流。這樣我們就得到了一個更大的流,他的流量是之前的流量+delta,而這條路就叫做增廣路. From 網絡流(Network Flow)

則我們稱這條路徑為一條增廣路徑,簡稱增廣路。

好了,弄懂了一些定義,接下來就可以介紹著名的Ford-Fulkerson算法了。

如圖所示,如果我們每次都找出一條增廣路,只要這條增廣路經過匯點,那說明此時水流還可以增加,增加的量為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;
}

總結

以上是生活随笔為你收集整理的网络流的最大流入门(从普通算法到dinic优化)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。