agc034D - Manhattan Max Matching

题目大意

题解

直接费用流连边有n^2条边,所以考虑新建四个点分别表示四种绝对值情况,然后和这四个点连即可

因为求的是最大值所以没有问题

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 abs(x) ((x)>0?(x):-(x))
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define inf 2000000000
#define ll long long
//#define file
using namespace std;

int a[20011][4],ls[2011],g[2011],X[2001],Y[2001],c[2001],d[1000001],n,i,j,k,l,len,st,ed,h,t;
ll f[2011],ans;
bool bz[2011];

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

int main()
{
	#ifdef file
	freopen("agc034d.in","r",stdin);
	#endif
	
	scanf("%d",&n);st=n*2+1,ed=n*2+2;len=1;
	fo(i,1,n*2) scanf("%d%d%d",&X[i],&Y[i],&c[i]);
	fo(i,1,n) New(st,i,c[i],0),New(i,ed+1,c[i],X[i]+Y[i]),New(i,ed+2,c[i],X[i]-Y[i]),New(i,ed+3,c[i],-X[i]+Y[i]),New(i,ed+4,c[i],-X[i]-Y[i]);
	fo(i,n+1,n+n) New(i,ed,c[i],0),New(ed+1,i,c[i],-(X[i]+Y[i])),New(ed+2,i,c[i],-(X[i]-Y[i])),New(ed+3,i,c[i],-(-X[i]+Y[i])),New(ed+4,i,c[i],-(-X[i]-Y[i]));
	
	while (1)
	{
		memset(f,128,sizeof(f));
		h=0;t=1;
		d[1]=st;f[st]=0;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\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-09-10 22:09  gmh77  阅读(122)  评论(0编辑  收藏  举报