题意

    有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算法 最小乘积最大权匹配的更多相关文章

  1. [BZOJ 3571] 画框

    Link: BZOJ 3571 传送门 Solution: 和 BZOJ2395 的建模完全相同,(BZOJ2395 题解传送门) 仅仅是将其中的基础问题由最小生成树改成了二分图最大完美匹配 只要将原 ...

  2. hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))

    Special Fish Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  3. hdu 3488(KM算法||最小费用最大流)

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  4. 运动员最佳匹配问题 KM算法:带权二分图匹配

    题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...

  5. hdu 4862 KM算法 最小K路径覆盖的模型

    http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过全部的点一次而且只一次. 建图是问题: 我自己最初就把n*m 个点分别放入 ...

  6. bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...

  7. BZOJ.1497.[NOI2006]最大获利(最小割 最大权闭合子图Dinic)

    题目链接 //裸最大权闭合子图... #include<cstdio> #include<cctype> #include<algorithm> #define g ...

  8. km板子(二分图最大权匹配)

    //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack- ...

  9. 二分图带权匹配、最佳匹配与KM算法

    ---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和 ...

随机推荐

  1. DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead extract-text-webpack-plugin 提取css报错

    深入浅出Webpack 1-5 使用pulugin extract-text-webpack-plugin 提取css报错 DeprecationWarning: Tapable.plugin is ...

  2. 36 - 网络编程-TCP编程

    目录 1 概述 2 TCP/IP协议基础 3 TCP编程 3.1 通信流程 3.2 构建服务端 3.3 构建客户端 3.4 常用方法 3.4.1 makefile方法 3.5 socket交互 3.4 ...

  3. Python标准库笔记(5) — sched模块

    事件调度 sched模块内容很简单,只定义了一个类.它用来最为一个通用的事件调度模块. class sched.scheduler(timefunc, delayfunc)这个类定义了调度事件的通用接 ...

  4. LDA线性判别分析

    LDA线性判别分析 给定训练集,设法将样例投影到一条直线上,使得同类样例的投影点尽可能的近,异类样例点尽可能的远,对新样本进行分类的时候,将新样本同样的投影,再根据投影得到的位置进行判断,这个新样本的 ...

  5. module 'pytest' has no attribute 'allure'问题解决

    安装allure后执行命令后报错module 'pytest' has no attribute 'allure' C:\Users\Desktop\xin>pytest -s -q --all ...

  6. PDFRender4NET的使用之pdf转图片

    同样的需要第三方的.dll,http://www.o2sol.com/pdfview4net/download.htm using O2S.Components.PDFRender4NET; usin ...

  7. .htaccess技巧: URL重写(Rewrite)与重定向(Redirect)

    URL重定向是.htaccess的重头戏,它可以将长地址转为短地址.将动态地址转为静态地址.重定向丢失的页面.防止盗链.实现自动语言转换等.笔者觉得难点是在正则表达式的运用和理解上. 实现所有这些神奇 ...

  8. 蓝图-BluePrint

    蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...

  9. C语言的第一天

    代码根本C语言(我不知道这句话,严不严谨) 2019年4月30日(day01) 软件Code::blocks #include <stdio.h> //导入标准的io库 #include ...

  10. 【LOJ】 #2008. 「SCOI2015」小凸想跑步

    题解 一道想法很简单的计算几何(由于我半平面交总是写不对,我理所当然的怀疑半平面交错了,事实上是我直线建错了) 首先我们对于两个凸包上的点设为\((x_0,y_0)\)和\((x_1,y_1)\)(逆 ...