[AGC034D]Manhattan Max Matching:费用流
前置姿势
\(k\)维空间内两点曼哈顿距离中绝对值的处理
戳这里:[CF1093G]Multidimensional Queries
多路增广的费用流
据说这个东西叫做ZKW费用流?
流程其实很简单,就是把EK中的单路回溯改成利用DFS多路增广,类似Dinic那样,可以看作是EK的一个优化。需要注意的是要标记从源点到当前点的路径,以免陷入零环无法自拔。
代码
bool spfa(){
memset(dis,0x3f,sizeof dis);
rin(i,1,n)cur[i]=head[i];
while(!q.empty())q.pop();
dis[s]=0,book[s]=true;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
trav(i,x){
int ver=e[i].to;
if(e[i].cap&&dis[ver]>dis[x]+e[i].cost){
dis[ver]=dis[x]+e[i].cost;
if(!book[ver]){
book[ver]=true;
q.push(ver);
}
}
}
book[x]=false;
}
return dis[t]<1e9;
}
int dfs(int x,int pref){
if(x==t||!pref)return pref;
int temp=0,flow=0;insta[x]=true;
for(int &i=cur[x];i;i=e[i].nxt){
int ver=e[i].to;if(insta[ver])continue;
if(dis[ver]==dis[x]+e[i].cost&&(temp=dfs(ver,std::min(pref,e[i].cap)))){
e[i].cap-=temp;
e[i^1].cap+=temp;
flow+=temp;
pref-=temp;
mincost+=temp*e[i].cost;
if(!pref)break;
}
}
insta[x]=false;
return flow;
}
void ek(){
while(spfa())maxflow+=dfs(s,1e9);
}
分析
显然费用流,直接建图的话每一对红球和蓝球(的位置)都需要连边,一共要连\(O(N^2)\)条边,再跑费用流的话显然时间爆炸。
注意到把绝对值拆开后\((x,y)\)系数只有\(2^2\)种可能性,并且两个球的距离是这四种情况中最大值,所以我们可以对四种情况分开处理,因为我们知道一对匹配的费用取的一定是最大值,即这两个球的距离。
具体如何建图可以参考代码。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(int i=(a);i<=(b);++i)
#define irin(i,a,b) for(int i=(a);i>=(b);--i)
#define trav(i,a) for(int i=head[a];i;i=e[i].nxt)
#define Size(a) (int)a.size()
#define pb push_back
#define mkpr std::make_pair
#define fi first
#define se second
#define lowbit(a) ((a)&(-(a)))
typedef long long LL;
using std::cerr;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=1005;
int n,s,t,ecnt=1,head[MAXN<<1];
struct Edge{
int to,nxt,cap,cost;
}e[MAXN*20];
inline void add_edge(int bg,int ed,int ca,int co){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
e[ecnt].cap=ca;
e[ecnt].cost=co;
head[bg]=ecnt;
}
int maxflow,cur[MAXN<<1];
LL mincost,dis[MAXN<<1];
bool book[MAXN<<1],insta[MAXN<<1];
std::queue<int> q;
bool spfa(){
memset(dis,0x3f,sizeof dis);
rin(i,1,t)cur[i]=head[i];
while(!q.empty())q.pop();
dis[s]=0,book[s]=true;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
trav(i,x){
int ver=e[i].to;
if(e[i].cap&&dis[ver]>dis[x]+e[i].cost){
dis[ver]=dis[x]+e[i].cost;
if(!book[ver]){
book[ver]=true;
q.push(ver);
}
}
}
book[x]=false;
}
return dis[t]<1e18;
}
int dfs(int x,int pref){
if(x==t||!pref)return pref;
int temp=0,flow=0;insta[x]=true;
for(int &i=cur[x];i;i=e[i].nxt){
int ver=e[i].to;if(insta[ver])continue;
if(dis[ver]==dis[x]+e[i].cost&&(temp=dfs(ver,std::min(pref,e[i].cap)))){
e[i].cap-=temp;
e[i^1].cap+=temp;
flow+=temp;
pref-=temp;
mincost+=1ll*temp*e[i].cost;
if(!pref)break;
}
}
insta[x]=false;
return flow;
}
void ek(){
while(spfa())maxflow+=dfs(s,1e9);
}
int main(){
n=read();
int x0=n*2+1,x1=x0+1,x2=x1+1,x3=x2+1;
s=x3+1,t=s+1;
rin(i,1,n){
int rx=read(),ry=read(),rc=read();
add_edge(s,i,rc,0);
add_edge(i,s,0,0);
add_edge(i,x0,1e9,rx+ry);
add_edge(x0,i,0,-rx-ry);
add_edge(i,x1,1e9,rx-ry);
add_edge(x1,i,0,-rx+ry);
add_edge(i,x2,1e9,-rx+ry);
add_edge(x2,i,0,rx-ry);
add_edge(i,x3,1e9,-rx-ry);
add_edge(x3,i,0,rx+ry);
}
rin(i,1,n){
int bx=read(),by=read(),bc=read();
add_edge(n+i,t,bc,0);
add_edge(t,n+i,0,0);
add_edge(x0,n+i,1e9,-bx-by);
add_edge(n+i,x0,0,bx+by);
add_edge(x1,n+i,1e9,-bx+by);
add_edge(n+i,x1,0,bx-by);
add_edge(x2,n+i,1e9,bx-by);
add_edge(n+i,x2,0,-bx+by);
add_edge(x3,n+i,1e9,bx+by);
add_edge(n+i,x3,0,-bx-by);
}
ek();
printf("%lld\n",-mincost);
return 0;
}
[AGC034D]Manhattan Max Matching:费用流的更多相关文章
- 【杂题】[AGC034D] Manhattan Max Matching【费用流】
Description 有一个无限大的平面,有2N个位置上面有若干个球(可能重复),其中N个位置是红球,N个位置是蓝球,红球与蓝球的总数均为S. 给出2N个位置和上面的球数,现要将红球与蓝球完美匹配, ...
- @atcoder - AGC034D@ Manhattan Max Matching
目录 @description@ @solution@ @accepted code@ @details@ @description@ 考虑一个二维平面,执行共 2*N 次操作: 前 N 次,第 i ...
- 「AGC034D」 Manhattan Max Matching
「AGC034D」 Manhattan Max Matching 传送门 不知道这个结论啊... (其实就是菜嘛) 首先 \(O(n^2)\) 的建边显然不太行. 曼哈顿距离有这样一个性质,如果将绝对 ...
- [2019多校联考(Round 6 T3)]脱单计划 (费用流)
[2019多校联考(Round 6 T3)]脱单计划 (费用流) 题面 你是一家相亲机构的策划总监,在一次相亲活动中,有 n 个小区的若干男士和 n个小区的若干女士报名了这次活动,你需要将这些参与者两 ...
- BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]
3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 960 Solved: 5 ...
- 洛谷 1004 dp或最大费用流
思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...
- bzoj4514: [Sdoi2016]数字配对--费用流
看了一眼题目&数据范围,觉得应该是带下界的费用流 原来想拆点变成二分图,能配对的连边,跑二分图,可行性未知 后来看到另外一种解法.. 符合匹配要求的数要满足:质因子的个数相差为1,且两者可整除 ...
- BZOJ-3130 费用流 (听题目胡扯丶裸最大流) 二分判定+最大流+实数精度乱搞
DCrusher爷喜欢A我做的水题,没办法,只能A他做不动的题了.... 3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec ...
- 【TYVJ】1982 武器分配(费用流)
http://tyvj.cn/Problem_Show.aspx?id=1982 一眼题.. 源向每个人连容量为1,费用为0的边. 每个人向一个中转节点na连容量1,费用0的边(你也可以不连,直接连后 ...
随机推荐
- n=C(2,n)+k(构造)( Print a 1337-string)Educational Codeforces Round 70 (Rated for Div. 2)
题目链接:https://codeforc.es/contest/1202/problem/D 题意: 给你一个数 n ( <=1e9 ),让你构造137713713.....(只含有1,3,7 ...
- Python应用RabbitMQ教程
介绍 RabbitMQ是一个消息代理.它的工作就是接收和转发消息.你可以把它想像成一个邮局:你把信件放入邮箱,邮递员就会把信件投递到你的收件人处.在这个比喻中,RabbitMQ就扮演着邮箱.邮局以及邮 ...
- 第六篇 ajax
加载异步数据 6-1 加载异步数据 XMLHttpRequest--传统的JavaScript方法实现Ajax功能 6-1-a <!DOCTYPE html PUBLIC "-//W3 ...
- Docker简易使用手册
1. Docker介绍 Docker中文社区文档 Docker 是一个开源的软件部署解决方案. Docker 包括三个基本概念: 镜像(Image) Docker的镜像概念类似于虚拟机里的镜像,是一个 ...
- java实现生产者和消费者问题
Java实现生产者和消费者问题 欢迎访问我的个人博客,获取更多有用的东西 链接一 链接二 也可以关注我的微信订阅号:CN丶Moti
- microsoft office powerpoibt automation 二次开发
背景 首先office的产品powerpoint是支持二次开发的,这里的二次开发并不是指在powerpoint产品中嵌入一些自己的控件,而是一些简单的automation的控制(进入放映状态,上一页, ...
- window.location.href 与 window.location.href 的区别
- centos7.3安装docker
一.写随笔的原因:最近在阿里云上买了个centos7.3服务器,想将一些demo运行在上面,所以需要做一些环境的安装,通过此篇文章MAKR一下.下面来记录下安装步骤(参考网上的一些教程,有坑的话会实时 ...
- jieba:我虽然结巴,但是我会分词啊
介绍 jieba目前是一款比较好分词模块 分词 import jieba # 可以使用jieba.cut进行分词 sentence = "失去恋人所带来的苦痛远远超过了他的承受范围" ...
- linux版宝塔安装Redis
1安装服务 2配置设置 3安装PHP扩展 首先,我们来安装服务,进入管理面板--软件管理--运行环境--redis-点击安装,等待完成 完成之后开始第二步,配置设置.这一步根据自己需要进行配置.注意安 ...