【bzoj3751】 Hnoi2014—画框
http://www.lydsy.com/JudgeOnline/problem.php?id=3571 (题目链接)
题意
给出一个$2*N$个点的二分图,$N*N$条边,连接$i$和$j$的边有两个权值$A[i][j]$和$B[i][j]$。求$A$的和与$B$的和之积最小是多少。
Solution
很经典的一个模型,右转题解→_→:http://blog.csdn.net/thy_asdf/article/details/50382556
对于一类乘积最小的题目的方法,我们都可以把每种方案的$x$之和与$y$之和作为它们的坐标$(x,y)$
要让乘积最小,那么作为答案的点一定在下凸壳上
我们先求出$x$最小的方案的坐标,再求出$y$最小的方案的坐标
这就是凸壳的两个端点$A$和$B$
然后考虑分治,每次找出离直线$AB$最远的点$C$,再继续递归处理
要使距离最远,那么就是使向量$AB$与$AC$的叉积最大
即最大化:$(c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)$
即:$c.x*(b.y-a.y)+c.y*(a.x-b.x)-a.x*(b.y-a.y)+a.y*(b.x-a.x)$
后面一部分是常数不用管,我们只要使$c.x*(b.y-a.y)+c.y*(a.x-b.x)$最大化
那么把$A[i][j]*(b.y-a.y)+B[i][j]*(a.x-b.x)$做$i$匹配$j$的边权
跑一遍KM求出最大匹配即可得出叉积最大的匹配
对于其他的最小乘积XXX,就类似地每次跑一遍XXX的算法求出离$AB$最远的方案即可
直到不可以继续细分下去就返回两端点的匹配较小的一个即可
虽然可以通过把所有方案构造在凸壳上卡掉这个算法,但随机情况下还是很快的
然而我还不会KM,还学习了一发KM。
对于边$(x,y)$
1.$x$,$y$都在当前匹配$lx[x]-=d$,$ly[y]+=d$和不变,原来在新图中,现在还在新图中;
2.$x$在,$y$不在,$lx[x]-=d$,$ly[y]$不变,原来不在新图中,现在和减小了,可能出现在新图中;
3.$x$不在,$y$在,$lx[x]$不变,$ly[y]+=d$,原来不在新图中,现在和变大了,不会进入新图中;
4.$x$,$y$都不在,那么$lx[x]$,$ly[y]$都不变,原来不在新图中,现在也不在新图中。
所以只有情况$2$会产生新边,不会有边消失,那么新图的边数会越来越大,直到找到一个完备匹配。
细节
听说这题卡常。。
这样是$O(n^4)$的,所以有一个优化,记录一个$slack$数组$slack[y]=min(lx[x]+ly[y]-g[x][y])$($x$与$y$有边)。每次求$d$就只要对不在匹配中的$y$的$slack$取$min$即可
代码
// bzoj3571
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define MOD 1000000007
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100;
int vx[maxn],vy[maxn],lx[maxn],ly[maxn],p[maxn],sla[maxn];
int n,g[maxn][maxn],A[maxn][maxn],B[maxn][maxn]; struct point {int x,y;
friend bool operator == (point a,point b) {
return a.x==b.x && a.y==b.y;
}
}L,R; int match(int x) {
vx[x]=1;
for (int y=1;y<=n;y++) if (!vy[y]) {
int t=lx[x]+ly[y]-g[x][y];
if (!t) {
vy[y]=1;
if (!p[y] || match(p[y])) {p[y]=x;return 1;}
}
else sla[y]=min(sla[y],t);
}
return 0;
}
point KM() {
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
memset(p,0,sizeof(p));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) lx[i]=max(lx[i],g[i][j]);
for (int x=1;x<=n;x++) {
memset(sla,0x7f,sizeof(sla));
while (1) {
memset(vx,0,sizeof(vx));memset(vy,0,sizeof(vy));
if (match(x)) break;
int d=inf;
for (int i=1;i<=n;i++) if (!vy[i]) d=min(d,sla[i]);
for (int i=1;i<=n;i++) {
if (vx[i]) lx[i]-=d;
if (vy[i]) ly[i]+=d;
}
}
}
point ans=(point){0,0};
for (int i=1;i<=n;i++) ans.x+=A[p[i]][i],ans.y+=B[p[i]][i];
return ans;
}
int solve(point l,point r) {
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) g[i][j]=A[i][j]*(r.y-l.y)+B[i][j]*(l.x-r.x);
point mid=KM();
if (l==mid || r==mid) return min(l.x*l.y,r.x*r.y);
return min(solve(l,mid),solve(mid,r));
}
int main() {
int T;scanf("%d",&T);
while (T--) {
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&A[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&B[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) g[i][j]=-A[i][j];
L=KM();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) g[i][j]=-B[i][j];
R=KM();
printf("%d\n",solve(L,R));
}
return 0;
}
【bzoj3751】 Hnoi2014—画框的更多相关文章
- 【LG3236】[HNOI2014]画框
[LG3236][HNOI2014]画框 题面 洛谷 题解 和这题一模一样. 将最小生成树换成\(KM\)即可. 关于复杂度,因为决策点肯定在凸包上,且\(n\)凸包的期望点数为\(\sqrt {\l ...
- bzoj 3571: [Hnoi2014]画框
Description 小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框.为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和.对于第 幅画与第 个画框的配对,小T都 ...
- [HNOI2014]画框
题目描述 小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框.为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和. 对于第 幅画与第 个画框的配对,小T都给出了这个配 ...
- BZOJ3571 & 洛谷3236:[HNOI2014]画框——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3571 https://www.luogu.org/problemnew/show/P3236 小T ...
- BZOJ3571 : [Hnoi2014]画框
题目是要求最小乘积最小权匹配, 将一种方案看做一个二维点(x,y),x=a值的和,y=b值的和,所有方案中只有在下凸壳上的点才有可能成为最优解 首先要求出两端的方案l,r两个点 l就是a值的和最小的方 ...
- bzoj3571: [Hnoi2014]画框 最小乘积匹配+最小乘积XX总结,
思路大概同bzoj2395(传送门:http://www.cnblogs.com/DUXT/p/5739864.html),还是将每一种匹配方案的Σai看成x,Σbi看成y,然后将每种方案转化为平面上 ...
- luogu P3236 [HNOI2014]画框
传送门 我们把一种方案的\(\sum a_{i,j}\)和\(\sum b_{i,j}\)看成点\((\sum a_{i,j},\sum b_{i,j})\),那么就只要求横纵坐标之积最小的点,类似于 ...
- BZOJ 3571 [Hnoi2014]画框(最小乘积完美匹配)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3571 [题目大意] 给出一张二分图,每条边上有a,b两个值,求完美匹配, 使得suma ...
- 洛谷P3236 [HNOI2014]画框(最小乘积KM)
题面 传送门 题解 我似乎连\(KM\)都不会打啊→_→ 和bzoj2395是一样的,只不过把最小生成树换成\(KM\)了.因为\(KM\)跑的是最大权值所以取个反就行了 //minamoto #in ...
随机推荐
- 高可用注册中心 ->Spring Cloud Eureka
在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况, 所以在生产 环境中必须对各个组件进行高可用部署, 对于微服务如此, 对于服务注册中心也一样. 但 是到本节为止,我们一直都在使用单节点 ...
- Datawhale MySQL 训练营 Task6 实战项目
作业 项目十:行程和用户(难度:困难) Trips 表中存所有出租车的行程信息.每段行程有唯一键 Id,Client_Id 和 Driver_Id 是 Users 表中 Users_Id 的外键.St ...
- 开源ETL工具kettle系列之常见问题
开源ETL工具kettle系列之常见问题 摘要:本文主要介绍使用kettle设计一些ETL任务时一些常见问题,这些问题大部分都不在官方FAQ上,你可以在kettle的论坛上找到一些问题的答案 1. J ...
- ubuntu HackRF One相关环境搭建
本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 HackRF链接:https://item.taobao.com/item.htm?spm=a1z10.1- ...
- 简介几种系统调用函数:write、read、open、close、ioctl
在 Linux 中,一切(或几乎一切)都是文件,因此,文件操作在 Linux 中是十分重要的,为此,Linux 系统直接提供了一些函数用于对文件和设备进行访问和控制,这些函数被称为系统调用(sysca ...
- SQL IF while 游标
-- if语句使用示例 declare @a int set @a=1 begin print @a =@a+1 end else begin print 'noooo' end -- while语句 ...
- JSBridge的原理
前言 参考来源 前人栽树,后台乘凉,本文参考了以下来源 github-WebViewJavascriptBridge JSBridge-Web与Native交互之iOS篇 Ios Android Hy ...
- 互评Beta版本-SkyHunter
基于NABCD评论作品,及改进建议 1.根据(不限于)NABCD评论作品的选题; N(Need,需求):飞机大战题材的游戏对80,90后的人来说算是童年的记忆,可以在闲暇之余打开电脑玩一会儿.但是 ...
- BugPhobia开发篇章:Scurm Meeting-更新至0x03
0x01 :目录与摘要 If you weeped for the missing sunset, you would miss all the shining stars 索引 提纲 整理与更新记录 ...
- Scrum Meeting 11.07
成员 今日任务 明日计划 用时 徐越 赵庶宏 薄霖 卞忠昊 JOSN数据解析 WebView和JavaScript交互基础 3h 武鑫 设计界面:独立完成一些简 ...