Kuhn-Munkras算法解决二分图最优权值匹配
在看这篇博文之前建议看一下上一篇匈牙利法解决二分图最大匹配问题:
https://www.cnblogs.com/fangxiaoqi/p/10808729.html
这篇博文参考自:https://www.cnblogs.com/logosG/p/logos.html
最优匹配
我们这里先说一下什么叫做最优匹配(也被称作最大带权分配)。
简而言之,最优匹配就是指在带权边的二分图中,求一个匹配使得匹配边上的权值和最大。
两个例子
例子1
出自wenr博客: http://www.cnblogs.com/wenruo/p/5264235.html
这也是一个拯救单身的例子。红线上的权值表示女生对男生的好感度,至于单身男青年,对于女生的期望为0(有妹子就行,不挑),最优权值匹配即好感度之和最大。
一:将女生的最大期望和男生的期望标出来,开始匹配。
==========================女1==========================
女1 X 男1 : 4 + 0 != 3 不匹配;
女1 X 男2: 4 + 0 = 4 匹配;
成功脱单。
==========================女2==========================
女2 X 男1: 3 + 0 != 2 不匹配;
女2 X 男2: 3 + 0 != 1 不匹配;
女2 X 男3: 3 + 0 = 3 匹配;
但是!男3 已经 名草有主了。
这时,男3 是个香饽饽,妹纸们都抢着要。男3对女生的期望 +1 ,而为了更好的分配,抢男生的妹子们要对男生的要求要降低一点
局势就变成这样了:
二:接下来就是一个递归的过程喽(下面的也是)
==========================女2==========================
女2 X 男1: 2 + 0 != 2 匹配;
成功脱单。
==========================女3==========================
女3 X 男3: 5 + 1 != 5 不匹配;
然后妹子3只能降低标准了。
==========================女3==========================
女3 X 男3: 4 + 1 != 5 匹配;
但是!男3有了吖。好叭,男3再次增加期望(渣男),妹子3和妹子1把要求降低一点。
妹子1尝试换人,去和妹子2抢男1。
但是!男1也有了吖。好叭,男1的期望+1,妹子2的期望降低一点。
妹子2尝试换人,去和男2匹配。
成功脱单。
最后,女1 X 男1,女2 X 男2,女3 X 男3 为最优匹配,大团圆结局。
而对于这种问题我们为什么要用KM算法?这显然是可以看出来的。但是,当单身男女数量越来越多,很难直接看出,而且如果仅仅用匈牙利算法找最大匹配然后比较每个最大匹配的权值来找最优匹配的实行难度也就越来越大,使用KM算法是一种好的选择。从上面的例子我们可以看出,KM算法是基于匈牙利方法进行不断进行递归和贪心的。
例子2
出自 https://www.cnblogs.com/logosG/p/logos.html
这是一个公司任免问题。
在一家公司里,有员工A,B,C,有三种工作a,b,c,如果员工和工作之间有线相连,则代表员工能胜任这份工作,而每个员工做每份工作的效率各不相同,图中的权值代表工作效率,而我们的目的就是做合适的安排保证最大的效率。
标出最大权值和右侧的期望。
==========================安排A==========================
A--a: 4 + 0 != 3 不匹配;
A--c: 4 + 0 = 4 匹配;
==========================安排B==========================
B--a: 3 + 0 != 2 不匹配;
B--b: 3 + 0 != 1 不匹配;
B--c: 3 + 0 != 3 匹配;但是产生冲突。
进行 -1 和 +1 的操作,来波递归。
B--a: 2 + 0 = 2 匹配。
==========================安排C==========================
C--c: 5 + 1 != 5 不匹配; 对C减1
C--c: 4 + 1 = 5 匹配但冲突;(情形类似于例1,递归和贪心即可)
最终,A--a,B--b,C--c。
KM算法的思想
KM算法是对匈牙利算法的一种贪心扩展,而其思想是通过给每个顶点一个标号(叫做顶标)来把求完备匹配(匈牙利算法求出完备匹配)下的最大权匹配问题(即最优分配)。通过修改某些点的符号(但要满足点标始终是可行的),不断增加图中可行边总数,直到图中存在仅由可行边组成的完全匹配为止,此时这个匹配一定是最佳的。
具体说一下最优匹配——定理:设$M$是一个带权完全二分图$G$的一个完备匹配,给每个顶点一个可行顶标(第$i$个$x$顶点的可行顶标用 $lx[i]$表示,第$j$个$y$顶点的可行顶标用 $ly[j]$ 表示),如果对所有的边$(i,j)$ in G,都有 $lx[i] + ly[j] \ge w[i,j]$ 成立($w\left[ {i,j} \right]$ 表示边的权),且对所有的边$(i,j)$ $in$ $M$,都有 $lx\left[ i \right] + ly\left[ j \right] = w\left[ {i,j} \right]$ 成立,则$M$是图$G$的一个最优匹配。
KM算法的步骤
1. 用邻接矩阵(或其他方法也行啦)来储存图,注意:如果只是想求最大权值匹配而不要求是完全匹配的话,请把各个不相连的边的权值设置为0。2. 运用贪心算法初始化标杆。3. 运用匈牙利算法找到完备匹配。4. 如果找不到,则通过修改标杆,增加一些边。5. 重复3,4的步骤,直到完全匹配时可结束。
KM算法的流程
(1)初始化可行顶标的值 (设定$lx$,$ly$的初始值) 。
(2)用匈牙利算法寻找相等子图的完备匹配。
(3)若未找到增广路则修改可行顶标的值。
重复(2)(3)直到找到相等子图的完备匹配为止。
参考自:http://www.cnblogs.com/zpfbuaa/p/7218607.html
hdoj 2255 奔小康赚大钱
我们以HDOJ2255为例。http://acm.hdu.edu.cn/showproblem.php?pid=2255
奔小康赚大钱
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15718 Accepted Submission(s): 6746
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱。由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内给出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万(当然是在他们的经济范围内)。.现在这个问题就是村领导怎样分配房子才能使收入最大(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的)?
Input
2
100 10
15 23
123
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f; int love[][]; // 每个妹子对每个男生的好感度
int ex_girl[]; // 每个妹子的期望值
int ex_boy[]; // 每个男生的期望值
bool vis_girl[]; // 每一轮匹配匹配过的女生
bool vis_boy[]; // 每一轮匹配匹配过的男生
int match[]; // 每个男生匹配到的妹子 如果没有则为-1
int slack[]; // 每个汉子如果能被妹子倾心最少还需要多少期望值
int n; bool dfs(int girl){
vis_girl[girl] = true;
for (int boy = ; boy < n; boy++) {
if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
if (gap == ) { // 如果符合要求
vis_boy[boy] = true;
if (match[boy] == - || 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
// 每个女生的初始期望值是与她相连的男生最大的好感度
for (int i = ; i < n; i++) {
ex_girl[i] = love[i][];
for (int j = ; j < n; j++) {
ex_girl[i] = max(ex_girl[i], love[i][j]);
}
}
// 尝试为每一个女生解决归宿问题
for (int i = ; i < n; i++) {
fill(slack, slack + n, INF); // 因为要取最小值 初始化为无穷大
while(){
// 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
// 记录每轮匹配中男生女生是否被尝试匹配过
memset(vis_girl, false, sizeof vis_girl);
memset(vis_boy, false, sizeof vis_boy);
if(dfs(i)) break; // 找到归宿 退出
// 如果不能找到 就降低期望值
// 最小可降低的期望值
int d = INF;
for (int j = ; j < n; j++)
if (!vis_boy[j]) d = min(d, slack[j]);
for (int 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;
}
}
}
// 匹配完成 求出所有配对的好感度的和
int res = ;
for (int i = ; i < n; i++)
res += love[match[i]][i];
return res;
}
int main(){
while (cin>>n) {
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
cin>>love[i][j];
cout<<KM()<<endl;
}
return ;
}
Kuhn-Munkras算法解决二分图最优权值匹配的更多相关文章
- POJ 2195 Going Home 【二分图最小权值匹配】
传送门:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- POJ-2195 Going Home---KM算法求最小权值匹配(存负边)
题目链接: https://vjudge.net/problem/POJ-2195 题目大意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格 ...
- POJ 3565 Ants 【最小权值匹配应用】
传送门:http://poj.org/problem?id=3565 Ants Time Limit: 5000MS Memory Limit: 65536K Total Submissions: ...
- 「日常温习」Hungary算法解决二分图相关问题
前言 二分图的重点在于建模.以下的题目大家可以清晰的看出来这一点.代码相似度很高,但是思路基本上是各不相同. 题目 HDU 1179 Ollivanders: Makers of Fine Wands ...
- 【uva 1349】Optimal Bus Route Design(图论--网络流 二分图的最小权完美匹配)
题意:有一个N个点的有向带权图,要求找若干个有向圈,使得每个点恰好属于一个圈.请输出满足以上条件的最小权和. 解法:有向圈?也就是每个点有唯一的后继.这是一个可逆命题,同样地,只要每个点都有唯一的后继 ...
- hdu1533 Going Home km算法解决最小权完美匹配
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- POJ 2125 Destroying The Graph 二分图 最小点权覆盖
POJ2125 题意简述:给定一个有向图,要通过某些操作删除所有的边,每一次操作可以选择任意一个节点删除由其出发的所有边或者通向它的所有边,两个方向有不同的权值.问最小权值和的解决方案,要输出操作. ...
- ZOJ-2342 Roads 二分图最小权值覆盖
题意:给定N个点,M条边,M >= N-1.已知M条边都有一个权值,已知前N-1边能构成一颗N个节点生成树,现问通过修改这些边的权值使得最小生成树为前N条边的最小改动总和为多少? 分析:由于计算 ...
- Dijkstra算法解决单源最短路径
单源最短路径问题:给定一个带权有向图 G = (V, E), 其中每条边的权是一个实数.另外,还给定 V 中的一个顶点,称为源.现在要计算从源到其他所有各顶点的最短路径长度.这里的长度是指路上各边权之 ...
随机推荐
- windows系统上 安装 Redis
下载地址:https://github.com/microsoftarchive/redis/releases 下载完成后,把这个给解压出来 然后,使用 cmd 命令 进入 解压的redis目录 输入 ...
- Ubuntu Linux虚拟机与windows快速创建共享文件夹
有时候我们需要在windows下与远程Linux服务器传输文件,之前使用pscp传输文件很方便,但不方便传输多文件,同时也不便于查看.看了网上的教程总结创建共享文件夹的流程: 1.首先在本地windo ...
- k8s 命令自动补全
yum install -y bash-completion source /usr/share/bash-completion/bash_completion source <(kubectl ...
- Codeforces Round #585 (Div. 2) D. Ticket Game
链接: https://codeforces.com/contest/1215/problem/D 题意: Monocarp and Bicarp live in Berland, where eve ...
- yii行为和过滤器
行为是对类的功能进行了扩展,针对开闭原则,为了类的扩展而生,不去修改类原有的代码. yii的行为需要继承yii\base\Behavior,这就好比你要给人安装一个胳膊,这个胳膊得是人的,而不能是老虎 ...
- request.getParameter乱码
String str= new String(request.getParameter("xxxx").getBytes("ISO-8859-1")," ...
- 下载文件设置header的filename要用ISO8859-1编码的原因
很多情况下,我们在写程序的时候都会把代码设置为UTF-8的编码,可以在下载文件设置filename的时候却有违常理,竟然设置编码格式为ISO8859-1,代码如下(如是英文的话就不需要这样处理了): ...
- luogu 3998 [SHOI2013]发微博 map
考试的时候被卡常了~ code: #include <bits/stdc++.h> #define ll long long #define N 200002 #define setIO( ...
- learning express step(八)
To skip the rest of the middleware functions from a router middleware stack, call next('route') to p ...
- [Luogu] 家族
https://www.luogu.org/problemnew/show/1767 字符串的读入有点麻烦 #include <cstdio> #include <cstring&g ...