AT_agc034_d [AGC034D] Manhattan Max Matching 题解

首先有个显然的费用流做法,可以直接把任意两异色点连边然后求匹配,但是边数太多无法通过。

考虑一个经典的转化:对于两点 \((x_1,y_1),(x_2,y_2)\) 之间的曼哈顿距离有 \(|x_1-x_2|+|y_1-y_2|=\max\{x_1+y_1-x_2-y_2,-x_1+y_1+x_2-y_2,x_1-y_1-x_2+y_2,-x_1-y_1+x_2+y_2\}\)。于是可以建四个点 \(A,B,C,D\),表示四种正负情况,建立如下费用流模型(\((a,b,c,d)\) 表示一条流量为 \(c\),费用为 \(d\)\(a\to b\) 的边):

  • 对于所有 \(1\le i\le n\)\((S,i,RC_i,0)\)
  • 对于所有 \(1\le i\le n\)\((n+i,T,BC_i,0)\)
  • 对于所有 \(1\le i\le n\)\((i,A,\infty,RX_i+RY_i)\)
  • 对于所有 \(1\le i\le n\)\((i,B,\infty,RX_i-RY_i)\)
  • 对于所有 \(1\le i\le n\)\((i,C,\infty,-RX_i+RY_i)\)
  • 对于所有 \(1\le i\le n\)\((i,D,\infty,-RX_i-RY_i)\)
  • 对于所有 \(1\le i\le n\)\((A,i+n,\infty,-BX_i-BY_i)\)
  • 对于所有 \(1\le i\le n\)\((B,i+n,\infty,-BX_i+BY_i)\)
  • 对于所有 \(1\le i\le n\)\((C,i+n,\infty,BX_i-BY_i)\)
  • 对于所有 \(1\le i\le n\)\((D,i+n,\infty,BX_i+BY_i)\)

边数降到了 \(\mathcal O(n)\),直接费用流做即可。

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 5003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
int n,m,s,t,tot=1,vr[100003],ed[100003],c[100003],nx[100003],now[mxn],hd[mxn];
ll ans,cost,d[mxn];
queue<int>q;
bool b[mxn];
const ll INF=1e18;
inline void add(int x,int y,int z,int cs){
	vr[++tot]=y,ed[tot]=z,c[tot]=cs,nx[tot]=hd[x],hd[x]=tot;
	vr[++tot]=x,ed[tot]=0,c[tot]=-cs,nx[tot]=hd[y],hd[y]=tot;
}
bool spfa(){
	memset(d,0xcf,sizeof(d));
	memcpy(now,hd,sizeof(hd));
	d[s]=0,b[s]=1,q.push(s);
	while(q.size()){
		int x=q.front();q.pop();b[x]=0;
		for(int i=hd[x],y;i;i=nx[i])if(ed[i]&&d[y=vr[i]]<d[x]+c[i]){
			d[y]=d[x]+c[i];
			if(!b[y])b[y]=1,q.push(y);
		}
	}
	return d[t]>-INF;
}
ll dfs(int x,int t,ll flow){
	if(x==t)return flow;
	b[x]=1;
	ll ans=0;
	for(int &i=now[x],y;i&&ans<flow;i=nx[i])if(ed[i]&&!b[y=vr[i]]&&d[y]==d[x]+c[i]){
		ll num=dfs(y,t,min(flow-ans,(ll)ed[i]));
		if(num){
			ans+=num,cost+=num*c[i];
			ed[i]-=num,ed[i^1]+=num; 
		}
	}
	b[x]=0;
	return ans;
}
signed main(){
	scanf("%d",&n);
	s=0,t=n*2+1;
	for(int i=1,x,y,c;i<=n;++i){
		scanf("%d%d%d",&x,&y,&c);
		add(s,i,c,0);
		add(i,t+1,c,x+y);
		add(i,t+2,c,x-y);
		add(i,t+3,c,-x+y);
		add(i,t+4,c,-x-y);
	}
	for(int i=1,x,y,c;i<=n;++i){
		scanf("%d%d%d",&x,&y,&c);
		add(n+i,t,c,0);
		add(t+1,n+i,c,-x-y);
		add(t+2,n+i,c,-x+y);
		add(t+3,n+i,c,x-y);
		add(t+4,n+i,c,x+y);
	}
	while(spfa()){
		ll x;
		while((x=dfs(s,t,INF)))ans+=x;
	}
	printf("%lld",cost);
    return 0;
}
posted @   zifanwang  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2024-02-28 联合省选 2024 游记
2024-02-28 [USACO13MAR]Farm Painting S 题解
2024-02-28 CF111D Petya and Coloring 题解
2024-02-28 CF1034E Little C Loves 3 III 题解
2024-02-28 P2065 [TJOI2011] 卡片 题解
2024-02-28 CF756D Bacterial Melee 题解
点击右上角即可分享
微信分享提示