1. 程式人生 > 實用技巧 >LOJ#117. 有源匯有上下界最小流

LOJ#117. 有源匯有上下界最小流

我們看到有源點和匯點的上下界最小流,即在可行流的基礎上要求流量最小。
我們先跑一遍可行流,設可行流為flow1flow1flow1
則最小流為可行流−-−還能向下浮動的流量flow2flow2flow2
其實我們可以發現還能向下浮動的流量就是從原圖匯點到原圖源點的最大流(感性理解)。
因此步驟為:
跑出一個有源匯上下界可行流,如果滿流則設其答案為flow1flow1flow1,否則不存在答案。
刪去從原圖匯點到原圖源點的邊。
跑從原圖匯點到原圖源點的最大流,設答案為flow2flow2flow2,則總答案ans=flow1−flow2ans=flow1-flow2ans=flow1−flow2。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn =59905;
const ll inf=1e18;
ll head[maxn],cnt;
struct E
{
	ll to,next,flow;
}e[maxn*50];
ll nex[maxn],dis[maxn];
void add(ll u,ll v,ll flow)
{
	e[cnt].to=v;
	e[cnt].flow=flow;
	e[cnt].next=head[u];
	head[u]=cnt++;
	
	e[cnt].to=u;
	e[cnt].flow=0;
	e[cnt].next=head[v];
	head[v]=cnt++;
	
}
ll n,m,st,ed,d[maxn],num=0;
void init()
{
	cnt=0;
	memset(head,-1,sizeof(head));
}
queue<ll>q;
bool bfs()
{
	while(!q.empty()) q.pop();
	for(ll i=0;i<=ed+1;i++) nex[i]=head[i],dis[i]=inf;
	q.push(st);dis[st]=0;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		//printf("u=%lld\n",u);
		for(ll i=head[u];i!=-1;i=e[i].next)
		{
			ll v=e[i].to,flow=e[i].flow;
			//printf(" v=%lld flow=%lld\n",v,flow);
			if((flow>0)&&(dis[v]==inf))
			{
				
				dis[v]=dis[u]+1;
				q.push(v);
				if(v==ed) return 1;
			}
		}
	}
	return 0;
}
ll dfs(ll u,ll w)
{
	if(u==ed) return w;
	ll y=0;
	for(ll i=nex[u];(i!=-1)&&w;i=e[i].next)
	{
		nex[u]=i;
		ll v=e[i].to,flow=e[i].flow;
		if((flow>0)&&(dis[u]+1==dis[v]))
		{
			ll k=dfs(v,min(flow,w));
			if(k==0) dis[v]=inf;
			y+=k;
			w-=k;
			e[i].flow-=k;
			e[i^1].flow+=k;
		}
	}
	return y;
}
ll slove()
{
	ll ans=0;
	while(bfs())
	{
		//for(int i=0;i<=ed;i++) printf("dis[%d]=%d\n",i,dis[i]);
		ans+=dfs(st,inf);
		//printf("-ans=%d\n",ans);
	}
	return ans;
}
int main()
{
	ll s1,t1;
	scanf("%lld %lld %lld %lld",&n,&m,&s1,&t1);
	init();st=0,ed=n+1;
	for(ll i=1;i<=m;i++)
	{
		ll u,v,x,y;
		scanf("%lld %lld %lld %lld",&u,&v,&x,&y);
		add(u,v,y-x);
		d[u]-=x;d[v]+=x;
	}
	
	num=0;
	for(ll i=1;i<=n;i++)
	{
		if(d[i]>0) add(st,i,d[i]),num+=d[i];
		if(d[i]<0) add(i,ed,-d[i]);
	}add(t1,s1,inf);
	ll ans=slove();
	//printf("ans=%lld\n",ans);
	if(ans!=num)
	{
		printf("please go home to sleep\n");
		return 0;
	}
	cnt--;
	st=t1,ed=s1;
	ans=e[cnt].flow;
	//printf("ans=%lld\n",ans);
	e[cnt].flow=e[cnt^1].flow=0;
	ans-=slove();
	printf("%lld\n",ans);
	return 0;
}