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=uf(i)−∑fromi=uf(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)
如果满流此时即可求出流②(否则无解),再加上流①即是满足题意的可行流
无源汇上下界可行流
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=210,M=(10310+N)*2;
int n,m,S,T;
int h[N],e[M],ne[M],l[M],f[M],idx;
int d[N],q[N],A[N],cur[N];
void add(int a,int b,int c,int d)// 下界c 上届d
{ //建图上界-下界e[idx]=b,ne[idx]=h[a],l[idx]=c,f[idx]=d-c,h[a]=idx++;e[idx]=a,ne[idx]=h[b],f[idx]=0,h[b]=idx++;
}
bool bfs()
{memset(d,-1,sizeof d);int tt=0,hh=0;d[S]=0,q[0]=S,cur[S]=h[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()
{cin>>n>>m;S=0,T=n+1;memset(h,-1,sizeof h);for(int i=1;i<=m;i++){int a,b,c,d;cin>>a>>b>>c>>d;add(a,b,c,d);A[b]+=c,A[a]-=c;}int tot=0;for(int i=1;i<=n;i++){if(A[i]>0) add(S,i,0,A[i]),tot+=A[i];else if(A[i]<0)add(i,T,0,-A[i]);}if(tot!=dinic())cout<<"NO\n";else{cout<<"YES\n";for(int i=0;i<2*m;i+=2)cout<<f[i^1]+l[i]<<'\n';// 流②+流①}return 0;
}
有源汇上下界最大流
连接一条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';}
}