【模板】最大流之上下界可行流
ACM模板
目錄
- 無(wú)源匯上下界可行流
- 有源匯上下界最大流
- 有源匯上下界最小流
無(wú)源匯上下界可行流
問(wèn)題: 給定一個(gè)網(wǎng)絡(luò),求一個(gè)流滿(mǎn)足:每條邊的流量處在給定的下界和上屆[lower,upper]之間,滿(mǎn)足流量守恒
首先我們?cè)谠W(wǎng)絡(luò)中確定一個(gè)全部是下界的流網(wǎng)絡(luò),當(dāng)然此流不一定是可行流因?yàn)槠?strong>不一定滿(mǎn)足流量守恒,不妨叫此流流①
此時(shí)問(wèn)題轉(zhuǎn)化成找到一個(gè)流②,每條邊的流量處在[0,upper-lower]之間,此流與之前的流①相加(流①+流②)滿(mǎn)足流量守恒,是一個(gè)可行流。顯然流②不一定是可行流,但是我們可以經(jīng)過(guò)以下調(diào)整將其變成一個(gè)可行流,從而能過(guò)求出流②
- 記A(u)=∑toi=uf(i)?∑fromi=uf(i)A(u)=\sum_{toi=u}f(i)-\sum_{fromi=u}f(i)A(u)=∑toi=u?f(i)?∑fromi=u?f(i)即流入減去流出
- 若A(u)>0A(u)>0A(u)>0,源點(diǎn)SSS向uuu點(diǎn)連邊,容量是A(u)A(u)A(u)
- 若A(u)<0A(u)<0A(u)<0,uuu點(diǎn)向匯點(diǎn)TTT連邊,容量是?A(u)-A(u)?A(u)
如果滿(mǎn)流此時(shí)即可求出流②(否則無(wú)解),再加上流①即是滿(mǎn)足題意的可行流
無(wú)源匯上下界可行流
有源匯上下界最大流
連接一條t->s下界是0上界是∞∞∞的邊,由此轉(zhuǎn)化循環(huán)流問(wèn)題(無(wú)源匯上下界可行流)
按照循環(huán)流問(wèn)題建圖,首先跑dinic看是否能夠找到一條可行流(即判斷是否是滿(mǎn)流)
然后在換源點(diǎn)和匯點(diǎn)并刪去t->s的邊再跑一邊dinic(榨干殘留網(wǎng)絡(luò)),可行流+第二次dinic即是最大流
心里沒(méi)有一點(diǎn)AC數(shù)的詳細(xì)證明
有源匯上下界最大流
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=210,M=(N+10000)*2; int h[N],e[M],ne[M],f[M],idx; int n,m,S,T; int d[N],q[N],cur[N],A[N]; void add(int a,int b,int c) {e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++; } bool bfs() {int tt=0,hh=0;memset(d,-1,sizeof d);d[S]=0,cur[S]=h[S],q[0]=S;while(hh<=tt){int t=q[hh++];for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]==-1&&f[i]){d[j]=d[t]+1;cur[j]=h[j];if(j==T) return 1;q[++tt]=j;}}}return 0; } int dfs(int u=S,int flow=0x3f3f3f3f) {if(u==T) return flow;int rmn=flow;for(int i=cur[u];i!=-1&&rmn;i=ne[i]){cur[u]=i;int j=e[i];if(d[j]==d[u]+1&&f[i]){int t=dfs(j,min(f[i],rmn));if(!t) d[j]=-1;f[i]-=t,f[i^1]+=t,rmn-=t;}}return flow-rmn; }int dinic() {int r=0;while(bfs()) r+=dfs();return r; } int main() {int s,t;cin>>n>>m>>s>>t;memset(h,-1,sizeof h);S=0,T=n+1;for(int i=1;i<=m;i++){int a,b,c,d;cin>>a>>b>>c>>d;add(a,b,d-c);A[a]-=c,A[b]+=c;}int tot=0;for(int i=1;i<=n;i++){if(A[i]>0)add(S,i,A[i]),tot+=A[i];else if(A[i]<0)add(i,T,-A[i]);}add(t,s,0x3f3f3f3f);if(dinic()!=tot) cout<<"No Solution\n";else{int f1=f[idx-1];S=s,T=t;f[idx-1]=f[idx-2]=0; //刪去 t->s的邊cout<<f1+dinic()<<'\n';} }有源匯上下界最小流
最小流=可行流+++s->t流
由于可行流固定,為了使結(jié)果最小即s->t流最小
由于 s->t的流= - t->s的流
如果t->s求最大流,那么s->t就是最小流,fs→t=?ft→sf_{s\to t}=-f_{t\to s}fs→t?=?ft→s? 這也是為什么相減的原因
有源匯上下界最小流
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N=50010,M=(N+126000)*2; int h[N],e[M],ne[M],f[M],idx; int n,m,S,T; int d[N],q[N],cur[N],A[N]; void add(int a,int b,int c) {e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++; } bool bfs() {int tt=0,hh=0;memset(d,-1,sizeof d);d[S]=0,cur[S]=h[S],q[0]=S;while(hh<=tt){int t=q[hh++];for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]==-1&&f[i]){d[j]=d[t]+1;cur[j]=h[j];if(j==T) return 1;q[++tt]=j;}}}return 0; } int dfs(int u=S,int flow=0x3f3f3f3f) {if(u==T) return flow;int rmn=flow;for(int i=cur[u];i!=-1&&rmn;i=ne[i]){cur[u]=i;int j=e[i];if(d[j]==d[u]+1&&f[i]){int t=dfs(j,min(f[i],rmn));if(!t) d[j]=-1;f[i]-=t,f[i^1]+=t,rmn-=t;}}return flow-rmn; }int dinic() {int r=0;while(bfs()) r+=dfs();return r; } int main() {int s,t;cin>>n>>m>>s>>t;memset(h,-1,sizeof h);S=0,T=n+1;for(int i=1;i<=m;i++){int a,b,c,d;cin>>a>>b>>c>>d;add(a,b,d-c);A[a]-=c,A[b]+=c;}int tot=0;for(int i=1;i<=n;i++){if(A[i]>0)add(S,i,A[i]),tot+=A[i];else if(A[i]<0)add(i,T,-A[i]);}add(t,s,0x3f3f3f3f);if(dinic()!=tot) cout<<"No Solution\n";else{int f1=f[idx-1];S=t,T=s;f[idx-1]=f[idx-2]=0; //刪去 t->s的邊cout<<f1-dinic()<<'\n';} }總結(jié)
以上是生活随笔為你收集整理的【模板】最大流之上下界可行流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【模板】EK求最大流、dinic求最大流
- 下一篇: 【模板】卡特兰数