CF708D. Incorrect Flow

题目大意

题解

直接按要求平衡即可,因为源汇可以出入所以要连n->1

贡献根据c<f和c>f讨论,一开始把c设作max(c,f),根据f的变化使c在>=f的情况下尽量靠近原c

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define inf 2000000000
#define ll long long
//#define file
using namespace std;

int a[100001][4],ls[103],g[103],d[1000001],b[101],n,m,i,j,k,l,len=1,x,y,z,c,h,t,st,ed;
ll f[103],ans;
bool bz[103];

void NEW(int x,int y,int f,int w) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=f;a[len][3]=w;}
void New(int x,int y,int f,int w) {NEW(x,y,f,w),NEW(y,x,0,-w);}

int main()
{
	#ifdef file
	freopen("CF708D.in","r",stdin);
	#endif
	
	scanf("%d%d",&n,&m),st=n+1,ed=n+2;
	fo(i,1,m)
	{
		scanf("%d%d%d%d",&x,&y,&c,&z),b[x]-=z,b[y]+=z;
		if (z<=c)
		New(y,x,z,1),New(x,y,c-z,1),New(x,y,inf,2);
		else
		New(y,x,z-c,0),New(y,x,c,1),New(x,y,inf,2),ans+=z-c;
	}
	fo(i,1,n)
	if (b[i]>0) New(st,i,b[i],0);
	else New(i,ed,-b[i],0);
	New(n,1,inf,0);
	
	while (1)
	{
		memset(f,127,sizeof(f)),f[st]=0;
		h=0,t=1;
		d[1]=st,bz[st]=1;
		while (h<t)
		{
			for (i=ls[d[++h]]; i; i=a[i][1])
			if (a[i][2] && f[d[h]]+a[i][3]<f[a[i][0]])
			{
				f[a[i][0]]=f[d[h]]+a[i][3],g[a[i][0]]=i;
				if (!bz[a[i][0]])
				d[++t]=a[i][0],bz[a[i][0]]=1;
			}
			bz[d[h]]=0;
		}
		if (f[ed]>=1152921504606846976ll) break;
		
		l=inf;
		for (i=ed; i!=st; i=a[g[i]^1][0]) l=min(l,a[g[i]][2]);
		ans+=f[ed]*l;
		for (i=ed; i!=st; i=a[g[i]^1][0]) a[g[i]][2]-=l,a[g[i]^1][2]+=l;
	}
	
	printf("%lld
",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13688057.html