有源汇有上下界的最小流(LOJ117)
一个有源汇有上下界的最小流的瞎那啥讲解
其实最小流和最大流个人感觉很类似,连接了超级源点和超级汇点之后跑完一次最大流,一个是再在除去超级源点和超级汇点跑一次最大流,一个是给源汇点连一个无限边求最大流,然后无限边的流量就是答案
因为一个相当于是要把残量网络剩下的流加起来,才是最大流,而这个跑过最大流后剩下的就是最小流了
当然必须要当前弧优化,否则跑不过去
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
const ll inf=1e15;
int str,des,cnt=1,adj[50050],tp[50050],nxt[500050],to[500050],lev[50050],low[500050],st,de,m,n;
ll def[50050],cap[500050];
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,long long 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 long long dinic( int u,ll flow)
{
if(u==des) return flow;
ll res=0,flw;
int v;
for(int &e=tp[u];e&&res<=flow;e=nxt[e])
{
if(cap[e]>0&&lev[u]+1==lev[v=to[e]])
{
int minn=dinic(v,min(flow-res,cap[e]));
cap[e]-=minn,cap[e^1]+=minn,res+=minn;
if(flow==res) return res;
}
}
return lev[u]=0,res;
}
inline long long solve(){
long long ans=0;
while(bfs()==true) {
memcpy(tp,adj,sizeof(adj));
ans+=dinic(str,inf);
}
return ans;
}
int main(){
n=read(),m=read(),st=read(),de=read();
int s,t;
ll up,down;
long long sum=0;
for(re 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=0,des=n+1;
for(re int i=1;i<=n;i++)
{
if(def[i]>0) addedge(i,des,def[i]);
if(def[i]<0) addedge(str,i,-def[i]);
}
sum=solve();
addedge(de,st,inf);
sum+=solve();
for(re int e=adj[des];e;e=nxt[e])
{
if(cap[e^1]>0)
{
cout<<"please go home to sleep"<<'\n';
return 0;
}
}
cout<<cap[cnt];
return 0;
}