题解 AT4994 【[AGC034D] Manhattan Max Matching】
justin_cao · · 题解
首先显然可以想到暴力建出二分图之后跑费用流,但是边数有
可以发现,曼哈顿距离有一个非常好的性质,就是把绝对值拆开,一共有四种情况,这四种情况的最大值一定是这个曼哈顿距离的值。
具体地说,就是:
那么可以将两个点独立地来看,也就是:
那么既然可以拆开来看的话,就可以不用两两连边了,在左右两排点中间开
但是需要注意的是,曼哈顿距离这个性质不适用于最小值。
code:
#include<bits/stdc++.h>
#define maxn 1010
#define inf 1000000007
using namespace std;
typedef long long ll;
int read()
{
int x=0,f=1;
char ch=getchar();
while(ch-'0'<0||ch-'0'>9){if(ch=='-') f=-1;ch=getchar();}
while(ch-'0'>=0&&ch-'0'<=9){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,p1,p2,p3,p4,s,t;
int head[maxn*2],nxt[maxn*20],to[maxn*20],c[maxn*20],v[maxn*20],tot=1;
void add(int x,int y,int z,int u)
{
++tot;
nxt[tot]=head[x];
head[x]=tot;
to[tot]=y;
c[tot]=z;
v[tot]=u;
}
void addx(int x,int y,int z,int u)
{
add(x,y,z,u);
add(y,x,0,-u);
}
ll ans;
ll dis[maxn*2];
int pre[maxn*2],pre_num[maxn*2],vis[maxn*2];
queue<int>q;
int spfa()
{
for(int i=1;i<=t;i++) dis[i]=-1e16;
q.push(s);dis[s]=0;vis[s]=1;
while(q.size())
{
int now=q.front();q.pop();vis[now]=0;
for(int i=head[now];i;i=nxt[i])
{
if(dis[to[i]]<dis[now]+v[i]&&c[i])
{
dis[to[i]]=dis[now]+v[i];
pre[to[i]]=now;
pre_num[to[i]]=i;
if(!vis[to[i]]) q.push(to[i]),vis[to[i]]=1;
}
}
}
if(dis[t]==-1e16) return 0;
int di=inf;
for(int i=t;i!=s;i=pre[i]) di=min(di,c[pre_num[i]]);
for(int i=t;i!=s;i=pre[i]) c[pre_num[i]]-=di,c[pre_num[i]^1]+=di;
ans+=dis[t]*di;
return di;
}
int main()
{
n=read();p1=2*n+1;p2=p1+1;p3=p2+1;p4=p3+1;s=p4+1;t=s+1;
for(int i=1;i<=n;i++)
{
int x=read(),y=read(),z=read();
addx(s,i,z,0);
addx(i,p1,inf,x+y);
addx(i,p2,inf,x-y);
addx(i,p3,inf,-x+y);
addx(i,p4,inf,-x-y);
}
for(int i=1;i<=n;i++)
{
int x=read(),y=read(),z=read();
addx(i+n,t,z,0);
addx(p1,i+n,inf,-x-y);
addx(p2,i+n,inf,-x+y);
addx(p3,i+n,inf,x-y);
addx(p4,i+n,inf,x+y);
}
while(spfa()){};
printf("%lld\n",ans);
return 0;
}