有源汇的上下界最大流
关于有源汇的上下界最大流
主要由两种做法
1、二分一个流量,然后跑一个最大流,看有没有能满足的可行流,能满足的流量的最大值就是答案了,复杂度(单次网络流复杂度*log最大流量)
反之我是不想写这个的,感觉写起很麻烦,而且二分的边界也不好调;
看方法二就可以了;
2、首先无论如何我们都需要先跑一次可行流的(不然连能不能流通都不知道)
然后我们就得到了个循环可行流
实际上可行流的流量就是源点s和汇点t的反向边的流量(这不用说了吧,可行流求的就是s到t的流量,反向边也就存的这个了)
最大流其实就是原来的可行流加上现在流量网路中可能还存在的增广路的流量,我们只需要把原来求可行流时的超级源点和超级汇点删去,再跑一次最大流就行了(因为原来的可行流会在找增广路的时候被退回去,也就是说答案相当于会直接加上可行流的流量)
代码(LOJ116)
#include<bits/stdc++.h>
using namespace std;
int str,des,cnt=1,adj[205],nxt[70000],to[70000],cap[70000],lev[1005],low[70000],st,de,def[205],m,n;
inline int read(){
char ch;
while((ch=getchar())<'0'||ch>'9'){;}
int res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res;
}
inline void addedge(int u,int v,int p)
{
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=p;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline bool bfs(){
int u,e,v;
queue<int> que;
memset(lev,-1,sizeof(lev));
que.push(str),lev[str]=0;
while(!que.empty())
{
u=que.front(),que.pop();
for(int e=adj[u];e;e=nxt[e])
{
if(cap[e]>0&&lev[v=to[e]]==-1)
{
lev[v]=lev[u]+1,que.push(v);
if(v==des) return true;
}
}
}
return false;
}
inline int dinic(const int &u,const int &flow)
{
if(u==des) return flow;
int res=0,v,flw;
for(int e=adj[u];e;e=nxt[e])
{
if(cap[e]>0&&lev[u]<lev[v=to[e]])
{
flw=dinic(v,min(cap[e],flow-res));
if(flw==0) lev[v]=-1;
cap[e]-=flw,cap[e^1]+=flw;
res+=flw;if(res==flow) break;
}
}
return res;
}
inline int solve(){
int ans=0;
while(bfs()) ans+=dinic(str,1<<30);
return ans;
}
int main(){
n=read(),m=read(),st=read(),de=read();
int s,t,up,down,sum=0;
for(int i=1;i<=m;i++)
{
s=read(),t=read(),down=read(),up=read();
addedge(s,t,up-down);
low[i]=down,def[s]+=down,def[t]-=down;
}
str=n+1,des=n+2;
for(int i=1;i<=n;i++)
{
if(def[i]>0) sum+=def[i],addedge(i,des,def[i]);
if(def[i]<0) addedge(str,i,-def[i]);
}
addedge(de,st,1<<30);
if(solve()==sum)
{
adj[str]=0,adj[des]=0;
str=st;
des=de;
cout<<solve()<<endl;
}
else cout<<"please go home to sleep"<<endl;
return 0;
}