[MOBAN]一些网络流模板
来自某chen姓dalao的粉色网络流回忆.
loj 116有源汇上下界最大流
记录x出度l-入度l的和为d(x),我们将边调整为r-l之后,对于d(x)>0 的点,表示他原本要给定的流量,现在流量不够他搞出去,那么就x向新建汇点连边d(x),否则新建源点向x连-d(x),同时,我们将t向s连边就转化为了无源汇可行流.跑完之后,必须保证新建源点连出去的是满流,这样保证残余网络是可行流sum1,删除新加的边,保留残量,跑一个最大流sum2,答案sum1+sum2, 最小流就是从汇点跑最大流退费,sum1-sum2;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 50005;
int n,m,s,t;
int S,T,tot;
int dis[maxn],cnt[maxn];
int en[maxn],nt[maxn],la[maxn],owo=1,v[maxn],lat[maxn];
void adg(int x,int y,int vv) {
en[++owo]=y; nt[owo]=la[x]; la[x]=owo; v[owo]=vv;
en[++owo]=x; nt[owo]=la[y]; la[y]=owo; v[owo]=0;
}
int sap(int x,int flow) {
if(x==T) return flow;
int dlt = 0;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(v[it]&&dis[y]+1==dis[x]) {
int tmp = sap(y,min(flow-dlt,v[it]));
v[it]-=tmp; v[it^1]+=tmp;
dlt+=tmp;
if(dlt==flow||dis[S]>=tot) return dlt;
}
}
cnt[dis[x]]--;
if(cnt[dis[x]]==0) dis[S] = tot;
dis[x]++;
cnt[dis[x]]++;
return dlt;
}
int d[maxn],SB;
int main() {
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++) {
int x,y,l,r; scanf("%d%d%d%d",&x,&y,&l,&r);
adg(x,y,r-l); d[y]-=l; d[x]+=l;
}
memcpy(lat,la,sizeof la);
tot = n; S = ++tot; T = ++tot;
adg(t,s,0x3f3f3f3f); SB = owo;
int all = 0 ;
for(int i=1;i<=n;i++) {
if(d[i]>0) all+=d[i],adg(i,T,d[i]);
if(d[i]<0) adg(S,i,-d[i]);
}
int flow = 0;
while(dis[S]<tot) flow+=sap(S,0x3f3f3f3f);
//cerr<<flow<<endl;
if(flow!=all) return puts("please go home to sleep"),0;
memcpy(la,lat,sizeof la);
flow = v[SB];
//cerr<<flow<<endl;
T = t; S = s;
for(int i=1;i<=tot;i++) dis[i]=cnt[i]=0; cnt[0]=0;
while(dis[s]<tot) flow+=sap(s,0x3f3f3f3f);
printf("%d",flow);
}

浙公网安备 33010602011771号