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 ...
随机推荐
- Java 线程池架构原理和源码解析(ThreadPoolExecutor)
在前面介绍JUC的文章中,提到了关于线程池Execotors的创建介绍,在文章:<java之JUC系列-外部Tools>中第一部分有详细的说明,请参阅: 文章中其实说明了外部的使用方式,但 ...
- 教程-Delphi调用C# WEBSERVICE(二)
第二步:将webserivce的WSDL导入到该dll工程中,如何导,方法至少有两种,我说简单的一种: file->new->other->WebService->WSDL ...
- nginx模块编程之获取客户ip及端口号
ngx_request_t结构体中有一个connection定义,该定义指向一个ngx_connection_t的结构体: 结构体定义如下: struct ngx_connection_s { voi ...
- 标准I/O之实现细节
在UNIX系统中,标准I/O库最终都要调用文件I/O(read.write等).每个标准I/O流都有一个与其相关联的文件描述符,可以对一个流调用fileno函数以获得其描述符. 注意,fileno不是 ...
- MVC - 模型验证
使用MVC的数据验证特性可以自动实现客户端验证和服务端验证 假设有一个Employee类 public class Employee { public int ID { get; set; } pub ...
- js 字符及字符串
1. 判断是否为null或者空字符 var == null var == undefined var == '' 2. 字符串及其分割 var arr = new Array(); //定义一数组 a ...
- 读书笔记-详解C程序开发中 .c和.h文件的区别
一个简单的问题:.c和.h文件的区别 学了几个月的C语言,反而觉得越来越不懂了.同样是子程序,可以定义在.c文件中,也可以定义在.h文件中,那这两个文件到底在用法上有什么区别呢? 2楼: 子程序不要定 ...
- linux上配置jdk+Apache
一:安装jdk下载将jdk加压后放到/usr/local目录下: [root@master ~]#chmod 755 jdk-6u5-linux-x64.bin [root@master ~]# ./ ...
- C#泛型比较大小
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 如何运用管理员身份运行cmd窗口?
所有程序 → 附件 → 命令行提示符 → 鼠标右键“以管理员身份运行”.