[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);
}
 
posted @ 2018-12-26 13:58  Newuser233  阅读(8)  评论(0编辑  收藏  举报