BZOJ 3571 画框 KM算法 最小乘积最大权匹配
题意
有n个画框和n幅画。若第i幅画和第j个画框配对,则有平凡度Aij和违和度Bij,一种配对方案的总体不和谐度为∑Aij*∑Bij。求通过搭配能得到的最小不和谐度是多少。 n <= 70.
分析
这题是最小乘积最大权匹配裸题,其做法类似最小乘积生成树。
每个方案可以表示为二维平面上的点,答案必然在下凸壳上。
具体要怎么找呢?其实是有一个这样的方法:找出横坐标或纵坐标最小的点a和b,找点的方法可以用KM。
找到这两个点就可以分治下去做了,找到离直线ab距离最大的点(当然要在直线ab下方)。
列出点线距离公式,由于要找的点是在直线ab的下方,那么绝对值就可以去掉,整理为Ax+By的最值,然后就化成了一维,继续用KM来找,如此递归下去做。
当然,最小乘积XXX的东西似乎都可以用上面的方法做,拓展到多维方法也是类似的。
程序
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream> using namespace std; const int maxn = ;
const int INF = 0x3fffffff;
bool visx[maxn], visy[maxn];
int linker[maxn], slack[maxn], lx[maxn], ly[maxn], w[maxn][maxn];
int n, a[maxn][maxn], b[maxn][maxn];
struct Point
{
int x, y;
Point (int x = , int y = ):
x(x), y(y) {}
bool operator == (const Point &AI) const
{
return AI.x == x && AI.y == y;
}
}; bool dfs(int x)
{
int y, temp;
visx[x] = true;
for (y = ; y <= n; ++y)
{
if (visy[y]) continue ;
temp = lx[x]+ly[y]-w[x][y];
if (temp == )
{
visy[y] = true;
if (linker[y] == - || dfs(linker[y]))
{
linker[y] = x;
return true;
}
}
else if (temp < slack[y]) slack[y] = temp;
}
return false;
} Point KM()
{
int i, j, x, y, d;
memset(ly, , sizeof(ly));
memset(linker, -, sizeof(linker));
for (i = ; i <= n; ++i)
{
lx[i] = -INF;
for (j = ; j <= n; ++j) lx[i] = max(lx[i], w[i][j]);
}
for (x = ; x <= n; ++x)
{
for (y = ; y <= n; ++y) slack[y] = INF;
while ()
{
memset(visx, , sizeof(visx));
memset(visy, , sizeof(visy));
if (dfs(x)) break ;
d = INF;
for (y = ; y <= n; ++y) if (!visy[y]) d = min(d, slack[y]);
for (i = ; i <= n; ++i) if (visx[i]) lx[i] -= d;
for (y = ; y <= n; ++y)
if (visy[y]) ly[y] += d;
else slack[y] -=d;
}
}
Point temp(, );
for (i = ; i <= n; ++i)
temp.x += a[linker[i]][i], temp.y += b[linker[i]][i];
return temp;
} int solve(Point p1, Point p2)
{
for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
w[i][j] = (p2.y-p1.y)*a[i][j]+(p1.x-p2.x)*b[i][j];
Point t = KM();
if (t == p1 || t == p2) return min(p1.x*p1.y, p2.x*p2.y);
return min(solve(p1, t), solve(t, p2));
} int main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
int T;
scanf("%d", &T);
while (T --)
{
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]);
Point p1, p2;
for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
w[i][j] = -a[i][j];
p1 = KM();
for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
w[i][j] = -b[i][j];
p2 = KM();
printf("%d\n", solve(p1, p2));
}
return ;
}
BZOJ 3571 画框 KM算法 最小乘积最大权匹配的更多相关文章
- [BZOJ 3571] 画框
Link: BZOJ 3571 传送门 Solution: 和 BZOJ2395 的建模完全相同,(BZOJ2395 题解传送门) 仅仅是将其中的基础问题由最小生成树改成了二分图最大完美匹配 只要将原 ...
- hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))
Special Fish Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- hdu 3488(KM算法||最小费用最大流)
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- hdu 4862 KM算法 最小K路径覆盖的模型
http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过全部的点一次而且只一次. 建图是问题: 我自己最初就把n*m 个点分别放入 ...
- bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...
- BZOJ.1497.[NOI2006]最大获利(最小割 最大权闭合子图Dinic)
题目链接 //裸最大权闭合子图... #include<cstdio> #include<cctype> #include<algorithm> #define g ...
- km板子(二分图最大权匹配)
//#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack- ...
- 二分图带权匹配、最佳匹配与KM算法
---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...
随机推荐
- 使用Burpsuite爆破弱口令教工号
使用Burpsuite爆破弱口令教工号 发表于 2015-11-18 | 分类于 Burpsuite | 1条评论 | 26次阅读 准备 所谓工欲善其事,必先利其器,首先当然是要下 ...
- 蓝色的cms网站后台管理模板——后台
链接:http://pan.baidu.com/s/1c138cwC 密码:9vy9
- java在CMD窗口执行程序的时候输入密码(隐藏一些敏感信息)
有时候我们需要从CMD窗口执行一些命令,有时候会输入一些敏感的信息,比如密码之类的东西,所以我们可以从控制台读取但是不希望别人看见我们的密码: import java.io.Console; /** ...
- Opencv 配置VS2012
开始接触图像处理有一段时间了,经过前期的调研,和相关入门知识的学习,开始接触一些图像处理应用的工具.Opencv是一个图像处理的开源库,由于其开放的协议架构,国内外很多科研机构和团队都在基于openc ...
- Linux kernel kfifo分析【转】
转自:https://zohead.com/archives/linux-kernel-kfifo/ 本文同步自(如浏览不正常请点击跳转):https://zohead.com/archives/li ...
- 关于text-decoration无法清除继承的问题
因为text-decoration的值可以叠加,所以即使设置了none,浏览器也是看成是叠加,而不是清除的意思.
- C/C++——C语言数组名与指针
版权声明:原创文章,转载请注明出处. 1. 一维数组名与指针 对于一维数组来说,数组名就是指向该数组首地址的指针,对于: ]; array就是该数组的首地址,如果我们想定义一个指向该数组的指针,我们可 ...
- google浏览器中,使用clockwork 来调试
参考:https://laravel-china.org/courses/laravel-package/1976/debugging-tool-under-chrome-itsgoingdclock ...
- C# 中DateTime的各种使用
获得当前系统时间: DateTime dt = DateTime.Now; Environment.TickCount可以得到“系统启动到现在”的毫秒值 DateTime now = DateTime ...
- 【PAT】1011. A+B和C (15)
1011. A+B和C (15) 给定区间[-231, 231]内的3个整数A.B和C,请判断A+B是否大于C. 输入格式: 输入第1行给出正整数T(<=10),是测试用例的个数.随后给出T组测 ...