【模板】最大流之上下界可行流
生活随笔
收集整理的這篇文章主要介紹了
【模板】最大流之上下界可行流
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ACM模板
目錄
- 無源匯上下界可行流
- 有源匯上下界最大流
- 有源匯上下界最小流
無源匯上下界可行流
問題: 給定一個網絡,求一個流滿足:每條邊的流量處在給定的下界和上屆[lower,upper]之間,滿足流量守恒
首先我們在原網絡中確定一個全部是下界的流網絡,當然此流不一定是可行流因為其不一定滿足流量守恒,不妨叫此流流①
此時問題轉化成找到一個流②,每條邊的流量處在[0,upper-lower]之間,此流與之前的流①相加(流①+流②)滿足流量守恒,是一個可行流。顯然流②不一定是可行流,但是我們可以經過以下調整將其變成一個可行流,從而能過求出流②
- 記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,源點SSS向uuu點連邊,容量是A(u)A(u)A(u)
- 若A(u)<0A(u)<0A(u)<0,uuu點向匯點TTT連邊,容量是?A(u)-A(u)?A(u)
如果滿流此時即可求出流②(否則無解),再加上流①即是滿足題意的可行流
無源匯上下界可行流
有源匯上下界最大流
連接一條t->s下界是0上界是∞∞∞的邊,由此轉化循環流問題(無源匯上下界可行流)
按照循環流問題建圖,首先跑dinic看是否能夠找到一條可行流(即判斷是否是滿流)
然后在換源點和匯點并刪去t->s的邊再跑一邊dinic(榨干殘留網絡),可行流+第二次dinic即是最大流
心里沒有一點AC數的詳細證明
有源匯上下界最大流
#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流
由于可行流固定,為了使結果最小即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';} }總結
以上是生活随笔為你收集整理的【模板】最大流之上下界可行流的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【模板】EK求最大流、dinic求最大流
- 下一篇: 情人节发多少红包合适 情人节发多少红包合