bzoj3571————2016——3——12(最小乘积匹配)
bzoj3571
传送门http://www.lydsy.com/JudgeOnline/problem.php?id=3571
题解:
——————来自伟大的thy大神 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,所有y都匹配到一个x
每个点都有一个顶标lx[i],ly[i],设ij匹配的权值为g[i][j]
那么要一直满足任意的一组顶标lx[i]+ly[j]>=g[i][j]
把所有lx[i]+ly[j]==g[i][j]的边拿出来之后的图,如果有完备匹配
那这个完备匹配就一定是最大权匹配。
简单理解就是这个匹配的权值此时一定是所有顶标的和
对于有不在新图中的边(a,b)的另一个匹配
因为g[a][b]<lx[a]+ly[b],所以这个匹配的权值要更小。
lx[i]初值设为max(g[i][j]),ly[i]初值设为0,就满足顶标的条件
然后我们要修改顶标权值,使之在满足条件的前提下,让更多的边进入新图中,才有可能得到一个完备匹配
把所有在当前新图中的匹配中的x的顶标lx[x]减去d,把所有在当前新图中的匹配中的y的顶标加上d
但我们还要满足lx[i]+ly[j]>=g[i][j]
所以d应该取不在当前匹配的y中的min(lx[x]+ly[y]-g[x][y])(x与y有边),这才可以使改变d后的图满足lx[i]+ly[j]>=g[i][j]
那么为什么这样会有新边增加?
对于边(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.xy都不在,那么lx[x],ly[y]都不变,原来不在新图中,现在也不在新图中。
所以只有2会产生新边,不会有边消失,那么新图的边数会越来越大,直到找到一个完备匹配。
代码:
#include<iostream> #include<cstring>
#include<cstdio>
#define inf 0x7fffffff
struct poi{int x,y;}le,ri;
int lx[],ly[],sla[];
int g[][],a[][],b[][],f[];
int n;
bool vx[],vy[];
bool operator ==(poi a,poi b){return a.x==b.x&&a.y==b.y;}
using namespace std;
bool dfs(int x)
{
vx[x]=true;
for (int y=; y<=n; y++)
{
if (!vy[y])
{
int t=lx[x]+ly[y]-g[x][y];
if (!t)
{
vy[y]=true;
if (!f[y]||dfs(f[y]))
{
f[y]=x;
return true;
}
}
else sla[y]=min(sla[y],t);
}
}
return false;
}
poi km()
{
memset(lx,,sizeof(lx)); memset(ly,,sizeof(ly)); memset(f,,sizeof(f));
for (int i=; i<=n; i++) for (int j=; j<=n; j++) lx[i]=max(lx[i],g[i][j]);
for (int x=; x<=n; x++)
{
memset(sla,,sizeof(sla));
while (true)
{
memset(vx,,sizeof(vx)); memset(vy,,sizeof(vy));
if (dfs(x)) break;
int d=inf;
for (int i=; i<=n; i++) if (!vy[i]) d=min(d,sla[i]);
for (int i=; i<=n; i++)
{
if (vx[i]) lx[i]-=d;
if (vy[i]) ly[i]+=d;
}
}
}
poi ans=(poi) {,};
for (int i=; i<=n; i++) ans.x+=a[f[i]][i], ans.y+=b[f[i]][i];
return ans;
}
int slove(poi l,poi r)
{
for(int i=; i<=n; i++) for (int j=; j<=n; j++) g[i][j]=a[i][j]*(r.y-l.y)+b[i][j]*(l.x-r.x);
poi mid=km();
if (l==mid||r==mid) return min(l.x*l.y,r.x*r.y);
else
return min(slove(l,mid),slove(mid,r));
}
int main()
{
int t;
scanf("%d",&t);
for (int z=; z<=t; z++)
{
scanf("%d",&n);
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]);
for (int i=; i<=n; i++) for (int j=; j<=n; j++) g[i][j]=-a[i][j];le=km();
for (int i=; i<=n; i++) for (int j=; j<=n; j++) g[i][j]=-b[i][j];ri=km();
printf("%d\n",slove(le,ri));
}
}
这样是O(n^4)的,所以有一个优化,记录一个slack数组 slack[y]=min(lx[x]+ly[y]-g[x][y])(x与y有边)
每次求d就只要对不在匹配中的y的slack取min即可
bzoj3571————2016——3——12(最小乘积匹配)的更多相关文章
- bzoj3571: [Hnoi2014]画框 最小乘积匹配+最小乘积XX总结,
思路大概同bzoj2395(传送门:http://www.cnblogs.com/DUXT/p/5739864.html),还是将每一种匹配方案的Σai看成x,Σbi看成y,然后将每种方案转化为平面上 ...
- 【算法】最小乘积生成树 & 最小乘积匹配 (HNOI2014画框)
今天考试的时候果然题目太难于是我就放弃了……转而学习了一下最小乘积生成树. 最小乘积生成树定义: (摘自网上一篇博文). 我们主要解决的问题就是当k = 2时,如何获得最小的权值乘积.我们注意到一张图 ...
- Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)
问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...
- BZOJ 3571 画框 KM算法 最小乘积最大权匹配
题意 有n个画框和n幅画.若第i幅画和第j个画框配对,则有平凡度Aij和违和度Bij,一种配对方案的总体不和谐度为∑Aij*∑Bij.求通过搭配能得到的最小不和谐度是多少. n <= 70. 分 ...
- BZOJ 3571 [Hnoi2014]画框(最小乘积完美匹配)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3571 [题目大意] 给出一张二分图,每条边上有a,b两个值,求完美匹配, 使得suma ...
- HDU(1853),最小权匹配,KM
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Other ...
- C语言 · 最小乘积(基本型)
问题描述 给两组数,各n个. 请调整每组数的排列顺序,使得两组数据相同下标元素对应相乘,然后相加的和最小.要求程序输出这个最小值. 例如两组数分别为:1 3 -5和-2 4 1 那么对应乘积取和的最小 ...
- 2016年12月31日 星期六 --出埃及记 Exodus 21:26
2016年12月31日 星期六 --出埃及记 Exodus 21:26 "If a man hits a manservant or maidservant in the eye and d ...
- 2016年12月30日 星期五 --出埃及记 Exodus 21:25
2016年12月30日 星期五 --出埃及记 Exodus 21:25 burn for burn, wound for wound, bruise for bruise.以烙还烙,以伤还伤,以打还打 ...
随机推荐
- springMVC简单的安全防御配置
1,使用 spring form 标签 防 csrf 攻击 2,标明请求方法:RequestMethod.GET,RequestMethod.POST, PATCH, POST, PUT, and D ...
- 转:Emmet 学习之路 - 2 基本语法
http://blog.csdn.net/jizhongchun/article/details/8472755 导读:Emmet的基本语法.学习步骤是:1 基本语法: 2 html命令: 3 css ...
- jq的事件冒泡
在页面上可以有多个事件,也可以多个元素响应同一件事, 事件冒泡引发的问题: 有些时候不想动用的事件,却因为事件冒泡而触发 解决问题: 1.事件对象 由于IE-DOM和标准的DOM实现事件对象的方法各不 ...
- Android开发实现HttpClient工具类
在Android开发中我们经常会用到网络连接功能与服务器进行数据的交互,为此Android的SDK提供了Apache的HttpClient来方便我们使用各种Http服务.你可以把HttpClient想 ...
- rstPixelType Constants
Constant Value Description PT_UNKNOWN -1 Pixel values are unknown. PT_U1 0 Pixel values are 1 bit. P ...
- SQL C# nvarchar类型转换为int类型 多表查询的问题,查询结果到新表,TXT数据读取到控件和数据库,生成在控件中的数据如何存到TXT文件中
在数据库时候我设计了学生的分数为nvarchar(50),是为了在从TXT文件中读取数据插入到数据库表时候方便,但是在后期由于涉及到统计问题,比如求平均值等,需要int类型才可以,方法是:Conver ...
- PHP 命名空间以及自动加载(自动调用的函数,来include文件)
这篇文章的目的是记录 1. php中的自动加载函数 __autoload(), 和 spl_autoload_register()函数, 2 .php中命名空间的使用. 一.当不使用命名空间的时候 a ...
- 贝塞尔曲线 & CAShapeLayer & Stroke 动画 浅谈
转载自:http://46aae4d1e2371e4aa769798941cef698.devproxy.yunshipei.com/qiaoqiaoqiao2014/article/details/ ...
- JAVA Timer定时器使用方法(二)
JAVA Timer 定时器测试 MyTask.java:package com.timer; import java.text.SimpleDateFormat;import java.util. ...
- CSS实现三角形方法一--rotate+relative
方法说明:两个正方形,一个小的,一个大的,将大的正方向进行旋转,然后移动到小的正方形的合适位置,覆盖小正方形的一部分,使小正方形剩余部分为三角形,再把大正方形的背景色改为浏览器窗口的颜色. 用到知识: ...