Kuhn-Munkres算法
KM算法——二分图最大权匹配
我们前面学过了二分图匹配的匈牙利算法。但这种算法是针对没有权值的图来说的。
肯定有人想问,没有权值的用匈牙利算法,哪有权值的图要求最大权或最小权匹配呢??
这里就引出了我们今天的主角——KM算法。
这种算法是怎么着呢? 其实最大和最小权匹配都是一样的问题。只要会求最大匹配,如果要求最小权匹配,则将权值取相反数,再把结果取相反数,那么最小权匹配就求出来了。
但问题在这么求最大权匹配呢??
再看这个问题之前我们先来搞清楚几个概念。
one
二分图的带权匹配:二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小。而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大或最小。二分图的带权匹配与最佳匹配不等价,也不互相包含。
这两个的关系比较悬乎。我的理解就是带权匹配是不考虑是不是完备,只求最大或最小权匹配。而最佳匹配则必须在完备匹配的基础上找最大或最小权匹配。
KM算法的运行要求是必须存在一个完备匹配,如果求一个最大权匹配(不一定完备)该如何办?依然很简单,把不存在的边权值赋为0。
KM算法求得的最大权匹配是边权值和最大,如果我想要边权之积最大,又怎样转化?还是不难办到,每条边权取自然对数,然后求最大和权匹配,求得的结果a再算出e^a就是最大积匹配。至于精度问题则没有更好的办法了。
two
二分图最优匹配:对于二分图的每条边都有一个权(非负),要求一种完备匹配方案,使得所有匹配边的权和最大,记做最优完备匹配。(特殊的,当所有边的权为1时,就是最大完备匹配问题)
three。
完备匹配:定义 设G=<V1,V2,E>为二部图,|V1|≤|V2|,M为G中一个最大匹配,且|M|=|V1|,则称M为V1到V2的完备匹配。
在上述定义中,若|V2|=|V1|,则完备匹配即为完美匹配,若|V1|<|V2|,则完备匹配为G中最大匹配。
KM算法
KM算法是通过给每个顶点一个标号(叫做顶标)来把求最大权匹配的问题转化为求完备匹配的问题的。设顶点Xi的顶标为A[i],顶点Yi的顶标为B[i],顶点Xi与Yj之间的边权为w[i,j]。在算法执行过程中的任一时刻,对于任一条边(i,j),A[i]+B[j]>=w[i,j]始终成立,初始A[i]为与xi相连的边的最大边权,B[j]=0。KM算法的正确性基于以下定理:
若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
因为对于二分图的任意一个匹配,如果它包含于相等子图,那么它的边权和等于所有顶点的顶标和;如果它有的边不包含于相等子图,那么它的边权和小于所有顶点的顶标和(即不是最优匹配)。所以相等子图的完备匹配一定是二分图的最大权匹配。
算法流程
(1)初始化可行顶标的值
(2)用匈牙利算法寻找完备匹配
(3)若未找到完备匹配则修改可行顶标的值
(4)重复(2)(3)直到找到相等子图的完备匹配为止
小总结:
KM算法是用来解决最大权匹配问题的,在一个二分图里,左顶点为x,右顶点为y,现对于每组左右连接连接XiYj有权wij,求一种匹配使得所有wij的和最大。
也就是说,最大匹配一定是完美匹配。(完美匹配:二分图的两边点数相同)
如果点数不相同,我们可以通过虚拟点权为0的点来时的点数相同,这也就使这个图变成了完美匹配。
代码实现:
#include <iostream> #include <cstring> #include <cstdio> using namespace std; ; const int INF = 0x3f3f3f3f; int love[MAXN][MAXN]; // 记录每个妹子和每个男生的好感度 int ex_girl[MAXN]; // 每个妹子的期望值 int ex_boy[MAXN]; // 每个男生的期望值 bool vis_girl[MAXN]; // 记录每一轮匹配匹配过的女生 bool vis_boy[MAXN]; // 记录每一轮匹配匹配过的男生 int match[MAXN]; // 记录每个男生匹配到的妹子 如果没有则为-1 int slack[MAXN]; // 记录每个汉子如果能被妹子倾心最少还需要多少期望值 int N; bool dfs(int girl) { vis_girl[girl] = true; ; boy < N; ++boy) { if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次 int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy]; ) { // 如果符合要求 vis_boy[boy] = true; || dfs( match[boy] )) { // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人 match[boy] = girl; return true; } } else { slack[boy] = min(slack[boy], gap); // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸 } } return false; } int KM() { memset(match, -, sizeof match); // 初始每个男生都没有匹配的女生 memset(ex_boy, , sizeof ex_boy); // 初始每个男生的期望值为0 // 每个女生的初始期望值是与她相连的男生最大的好感度 ; i < N; ++i) { ex_girl[i] = love[i][]; ; j < N; ++j) ex_girl[i] = max(ex_girl[i], love[i][j]); } // 尝试为每一个女生解决归宿问题 ; i < N; ++i) { fill(slack, slack + N, INF); // 因为要取最小值 初始化为无穷大 ) { // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止 // 记录每轮匹配中男生女生是否被尝试匹配过 memset(vis_girl, false, sizeof vis_girl); memset(vis_boy, false, sizeof vis_boy); if (dfs(i)) break; // 找到归宿 退出 // 如果不能找到 就降低期望值 // 最小可降低的期望值 int d = INF; ; j < N; ++j) if (!vis_boy[j]) d = min(d, slack[j]); ; j < N; ++j) { // 所有访问过的女生降低期望值 if (vis_girl[j]) ex_girl[j] -= d; // 所有访问过的男生增加期望值 if (vis_boy[j]) ex_boy[j] += d; // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步! else slack[j] -= d; } } } // 匹配完成 求出所有配对的好感度的和 ; ; i < N; ++i) res += love[ match[i] ][i]; return res; } int main() { while (~scanf("%d", &N)) { ; i < N; ++i) ; j < N; ++j) scanf("%d", &love[i][j]); printf("%d\n", KM()); } ; }
这有一篇博客讲的挺好的。
http://www.cnblogs.com/wenruo/p/5264235.html
Kuhn-Munkres算法的更多相关文章
- 二分图匹配--KM算法
Kuhn-Munkres算法 KM算法,求完备匹配下的最大权匹配,时间复杂度O(\(n^3\)) 所谓的完备匹配就是在二部图中,x点集中的所有点都有对应的匹配 且 y点集中所有的点都有对应的匹配 ,则 ...
- acm算法模板(1)
1. 几何 4 1.1 注意 4 1.2 几何公式 4 1.3 多边形 6 1.4 多边形切割 9 1.5 浮点函数 10 1.6 面积 15 1.7 球面 16 1.8 三角形 17 1.9 三维几 ...
- Kuhn-Munkres算法。带权二分图匹配模板 (bin神小改版本)
/****************************************************** 二分图最佳匹配 (kuhn munkras 算法 O(m*m*n)). 邻接矩阵形式 . ...
- HDU 2853 最大匹配&KM模板
http://acm.hdu.edu.cn/showproblem.php?pid=2853 这道题初看了没有思路,一直想的用网络流如何解决 参考了潘大神牌题解才懂的 最大匹配问题KM 还需要一些技巧 ...
- ACM-ICPC竞赛模板
为了方便打印,不再将代码放到代码编辑器里,祝你好运. ACM-ICPC竞赛模板(1) 1. 几何 4 1.1 注意 4 1.2 几何公式 4 1.3 多边形 6 1.4 多边形切割 9 1.5 浮点函 ...
- HDUOJ---------2255奔小康赚大钱
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- MATLAB实例:Munkres指派算法
MATLAB实例:Munkres指派算法 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 1. 指派问题陈述 指派问题涉及将机器分配给任务,将工人分配给 ...
- 分配问题与Hungarian算法
分配问题与Hungarian算法 分配问题 指派问题 匈牙利算法 匈牙利方法是一种能够在多项式时间内解决分配问题(assignment problem)的组合优化算法.它由Harold Kuhn 与1 ...
- 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- 匈牙利算法(Kuhn-Munkres)算法
这个算法有点难度,一般比较标准的描述网页上也有相关的描述,我在这里就简单的用十分通俗的语言给大家入个门 主要可以结合https://blog.csdn.net/zsfcg/article/detail ...
随机推荐
- Scrapy的安装--------Windows、linux、mac等操作平台
Scrapy安装 Scrapy的安装有多种方式,它支持Python2.7版本及以上或者是Python3.3版本及以上.下面来说py3环境下,scrapy的安装过程. Scrapy依赖的库比较多,至少需 ...
- 莫队+分块 BZOJ 3809
3809: Gty的二逼妹子序列 Time Limit: 80 Sec Memory Limit: 28 MBSubmit: 1634 Solved: 482[Submit][Status][Di ...
- 动态规划:双重DP
之前做过的传纸条那道题就是双重动态规划的典型应用,题意就不描述了,直接贴一下以前写过的,经典代码 #include<iostream> using namespace std; ,maxm ...
- Django之前端插件定制之表头
什么是插件? 插件只是辅助,是开发过程中的一个阶段.一般项目一期会用各种插件,迅速将功能.界面搭出来,二期时就改成自己的代码了.大点的公司都有自己的js库,自己开发类似jquery的库. 那接下来就写 ...
- 【并行计算】用MPI进行分布式内存编程(二)
通过上一篇中,知道了基本的MPI编写并行程序,最后的例子中,让使用0号进程做全局的求和的所有工作,而其他的进程却都不工作,这种方式也许是某种特定情况下的方案,但明显不是最好的方案.举个例子,如果我们让 ...
- 2016 ACM ICPC Asia Region - Tehran
2016 ACM ICPC Asia Region - Tehran A - Tax 题目描述:算税. solution 模拟. B - Key Maker 题目描述:给出\(n\)个序列,给定一个序 ...
- Codeforces Round #455 (Div. 2)
Codeforces Round #455 (Div. 2) A. Generate Login 题目描述:给出两个字符串,分别取字符串的某个前缀,使得两个前缀连起来的字符串的字典序在所有方案中最小, ...
- 【BubbleCup X】F:Product transformation
按照题解的规律,首先能看出前面每个数幂次的性质. 然后发掘约数的性质 #include<bits/stdc++.h> ; typedef long long ll; using names ...
- angular中使用AMEXIO
1.用NPM添加依赖到项目中,amexio需要先添加以下四个依赖到项目 npm install jquery@3.2.1 --save npm install bootstrap@4.0.0-alp ...
- svm和svr区别--摘自其它博客
学习笔记:SVM柔性边界的补充和SVR(支持向量回归) 作者 小刺猬yyx 关注 2016.08.06 10:31* 字数 1608 阅读 421评论 0喜欢 2 上一个笔记对于SVM不能完美分类的情 ...