[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); }