bzoj3571: [Hnoi2014]画框 最小乘积匹配+最小乘积XX总结,
思路大概同bzoj2395(传送门:http://www.cnblogs.com/DUXT/p/5739864.html),还是将每一种匹配方案的Σai看成x,Σbi看成y,然后将每种方案转化为平面上的点,再用km去找最远的点就行了。
然而几个月前就学过km且到现在还未写过一道km的题的我并不知道km如何对于负权给出最优解。。。。
#define XX 某传统算法(例如:最小生成树,二分图最优带权匹配什么的)
顺便总结一下最小乘积XX
即对于XX引入两个权值的概念(或是多个权值,一般是两个),看似无从下手,却可以将每一组可行解的方案的两个sum转化为平面内一个点,然后就可以发现一个十分优美的性质即最优解一定在凸包上,于是可以利用一种类似于快包算法的算法,依旧是用XX找出一定在凸包上的两个点,然后再次利用XX进行分治,递归地下去找,弄清楚边界条件(一般一个叉乘就可以轻松搞定),这样问题就被轻易地解决了。(貌似知道了这样的一个模板,基本所有类似问题都可以得到解决)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100
#define inf 100000000 int cases,n;
int a[maxn][maxn],b[maxn][maxn],val[maxn][maxn],slack[maxn],valx[maxn],valy[maxn],linky[maxn];
bool visx[maxn],visy[maxn]; struct point{
int x,y;
}ans; point operator -(point a,point b){return(point){a.x-b.x,a.y-b.y};}
double operator *(point a,point b){return a.x*b.y-a.y*b.x;} bool find(int x){
visx[x]=;
for (int y=;y<=n;y++)
if (!visy[y]){
int t=valx[x]+valy[y]-val[x][y];
if (!t){
visy[y]=;
if (!linky[y]||find(linky[y])){
linky[y]=x;
return ;
}
}
else slack[y]=min(slack[y],t);
}
return ;
} point km(){
memset(valx,,sizeof(valx));
memset(valy,,sizeof(valy));
memset(linky,,sizeof(linky));
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
valx[i]=max(valx[i],val[i][j]);
for (int x=;x<=n;x++){
memset(slack,,sizeof(slack));
while (){
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if (find(x)) break;
int d=inf;
for (int i=;i<=n;i++) if (!visy[i]) d=min(d,slack[i]);
for (int i=;i<=n;i++) if (visx[i]) valx[i]-=d;
for (int i=;i<=n;i++) if (visy[i]) valy[i]+=d;
}
}
point now={,};
for (int i=;i<=n;i++) now.x+=a[linky[i]][i],now.y+=b[linky[i]][i];
if ((ans.x==inf&&ans.y==inf)||(ans.x*ans.y>now.x*now.y)) ans=now;
return now;
} bool operator ==(point a,point b){return a.x==b.x&&a.y==b.y;} void solve(point x,point y){
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
val[i][j]=b[i][j]*(x.x-y.x)+a[i][j]*(y.y-x.y);
point z=km();
if ((z-x)*(y-z)<=) return;
solve(x,z);
solve(z,y);
} int main(){
scanf("%d",&cases);
while (cases--){
scanf("%d",&n);
ans.x=ans.y=inf;
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) scanf("%d",&a[i][j]);
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) scanf("%d",&b[i][j]);
point minx,miny;
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) val[i][j]=-a[i][j];
minx=km();
for (int i=;i<=n;i++)
for (int j=;j<=n;j++) val[i][j]=-b[i][j];
miny=km();
solve(minx,miny);
printf("%d\n",ans.x*ans.y);
}
return ;
}
bzoj3571: [Hnoi2014]画框 最小乘积匹配+最小乘积XX总结,的更多相关文章
- BZOJ3571 [Hnoi2014]画框 【分治 + KM算法】
题目链接 BZOJ3571 题解 如果知道最小乘积生成树,那么这种双权值乘积最小就是裸题了 将两权值和作为坐标,转化为二维坐标系下凸包上的点,然后不断划分分治就好了 这里求的是最小匹配值,每次找点套一 ...
- BZOJ3571 : [Hnoi2014]画框
题目是要求最小乘积最小权匹配, 将一种方案看做一个二维点(x,y),x=a值的和,y=b值的和,所有方案中只有在下凸壳上的点才有可能成为最优解 首先要求出两端的方案l,r两个点 l就是a值的和最小的方 ...
- 【算法】最小乘积生成树 & 最小乘积匹配 (HNOI2014画框)
今天考试的时候果然题目太难于是我就放弃了……转而学习了一下最小乘积生成树. 最小乘积生成树定义: (摘自网上一篇博文). 我们主要解决的问题就是当k = 2时,如何获得最小的权值乘积.我们注意到一张图 ...
- BZOJ 3571 [Hnoi2014]画框(最小乘积完美匹配)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3571 [题目大意] 给出一张二分图,每条边上有a,b两个值,求完美匹配, 使得suma ...
- bzoj3571————2016——3——12(最小乘积匹配)
bzoj3571 传送门http://www.lydsy.com/JudgeOnline/problem.php?id=3571 题解: ——————来自伟大的thy大神 http://blog.c ...
- GCJ:2008 Round1AA-Minimum Scalar Product(有序数组倒序乘积和最小)
题目链接:https://code.google.com/codejam/contest/32016/dashboard#s=p0 Minimum Scalar Product This contes ...
- BZOJ3571 & 洛谷3236:[HNOI2014]画框——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3571 https://www.luogu.org/problemnew/show/P3236 小T ...
- nyoj 237 游戏高手的烦恼 二分匹配--最小点覆盖
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=237 二分匹配--最小点覆盖模板题 Tips:用邻接矩阵超时,用数组模拟邻接表WA,暂时只 ...
- HDU(1853),最小权匹配,KM
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Other ...
随机推荐
- keystone 手动建立租户,用户,角色,服务,端口
建立租户: root@cloud:~# keystone tenant-create --name=admin WARNING: Bypassing authentication using a to ...
- IT的工作是这样?
天若有情天亦老,人干IT死得早; 谁知盘中餐,IT老加班; 锦瑟无端五十弦, 我做PM净贴钱; 庄生晓梦迷蝴蝶, 领导客户是大爷; 沧海月明珠有泪, 吃亏受气也开会; 蓝田日暖玉生烟, 可怜人生已跑偏 ...
- 最简单实现跨域的方法:用 Nginx 反向代理
本文作者: 伯乐在线 - 良少 .未经作者许可,禁止转载!欢迎加入伯乐在线 专栏作者. 什么是跨域 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascrip ...
- Hadoop概念学习系列之如何去找到历史版本的Hadoop发行包(三十四)
如何去找到历史版本的Hadoop发行包 找到Hadoop历史版本 这里我需要的Hadoop版本是2.0.3.打开hadoop的下载页面 http://www.apache.org/dyn/closer ...
- HTTP状态码及其含义 503 500 401 200 301 302
下表显示了常见的HTTP 1.1状态代码以及它们对应的状态信息和含义. 应当谨慎地使用那些只有HTTP 1.1支持的状态代码,因为许多浏览器还只能够支持HTTP 1.0.如果你使用了HTTP 1.1特 ...
- 利用ACE 自己实现的线程池
1: 线程池组件的配置文件: [log] ;DEBUG = 0 ;INFO = 1 ;WARN = 2 ;FAULT = 3 level=0 ;SCREENOUT = 0 ;FILEOUT = 1 ; ...
- SpringMVC学习系列 之 表单标签
http://www.cnblogs.com/liukemng/p/3754211.html 本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图 ...
- JS/JQ综合总结
总结 js部分 一 语法结构 1 区分大小写 2注意 //单行 /*多行注释*/ 3子面量(直接量 literal) 12//数字 5.8//小数 "hello"字符串 true ...
- Android应用换肤总结
换肤,我们都很熟悉,像XP的主题,塞班的主题.看过国外的一些技术博客,就会发现国内和国外对软件的,或者说移动开发的软件的需求的不同.国外用户注重社交.邮件等功能,国内用户则重视音乐.小说.皮肤等功能, ...
- 结构体数组(C++)
1.定义结构体数组 和定义结构体变量类似,定义结构体数组时只需声明其为数组即可.如: struct Student{ int num; char name[20]; char sex[5]; int ...