无源汇上下界可行流
问题: 给定一个网络,求一个流满足:每条边的流量处在给定的下界和上届[lower,upper]之间,满足流量守恒
首先我们在原网络中确定一个全部是下界的流网络,当然此流不一定是可行流因为其不一定满足流量守恒,不妨叫此流流①
此时问题转化成找到一个流②,每条边的流量处在[0,upper-lower]之间,此流与之前的流①相加(流①+流②)满足流量守恒,是一个可行流。显然流②不一定是可行流,但是我们可以经过以下调整将其变成一个可行流,从而能过求出流②
- 记 A ( u ) = ∑ t o i = u f ( i ) − ∑ f r o m i = u f ( i ) A(u)=\sum_{toi=u}f(i)-\sum_{fromi=u}f(i) A(u)=∑toi=uf(i)−∑fromi=uf(i)即流入减去流出
- 若 A ( u ) > 0 A(u)>0 A(u)>0,源点 S S S向 u u u点连边,容量是 A ( u ) A(u) A(u)
- 若 A ( u ) < 0 A(u)<0 A(u)<0, u u u点向汇点 T T T连边,容量是 − 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即是最大流
#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就是最小流, f s → t = − f t → s f_{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';
}
}