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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 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 题解