二分图最大权值匹配 KM算法 模板

大佬讲的太好了!!!太好了!!!

http://www.cnblogs.com/wenruo/p/5264235.html

KM算法用来求二分图最大权完美匹配。

本文配合该博文服用更佳趣写算法系列之--匈牙利算法

本文没有给出KM算法的原理,只是模拟了一遍算法的过程。另,博主水平较差,发现问题欢迎指出,谢谢!!!!

现在有N男N女,有些男生和女生之间互相有好感,我们将其好感程度定义为好感度,我们希望把他们两两配对,并且最后希望好感度和最大。

怎么选择最优的配对方法呢?

首先,每个女生会有一个期望值,就是与她有好感度的男生中最大的好感度。男生呢,期望值为0,就是……只要有一个妹子就可以啦,不挑~~

这样,我们把每个人的期望值标出来。

接下来,开始配对。

配对方法:

我们从第一个女生开始,分别为每一个女生找对象。

每次都从第一个男生开始,选择一个男生,使男女两人的期望和要等于两人之间的好感度

注意:每一轮匹配每个男生只会被尝试匹配一次!

具体匹配过程:

==============为女1找对象===============

(此时无人配对成功)

根据 “男女两人的期望和要等于两人之间的好感度”的规则

女1-男1:4+0 != 3

女1-男3:4+0 == 4

所以女1选择了男3

女1找对象成功

==============为女1找对象成功============

==============为女2找对象===============

(此时女1—男3)

根据配对原则,女2选择男3

男3有主女1,女1尝试换人

我们尝试让女1去找别人

尝试失败

为女2找对象失败!

==============为女2找对象失败============

这一轮参与匹配的人有:女1,女2,男3。

怎么办???很容易想到的,这两个女生只能降低一下期望值了,降低多少呢?

这轮

比如:女1选择男1,期望值要降低1。 女2选择男1,期望值要降低1。 女2选择男2,期望值要降低2。

于是,只要期望值降低1,就有妹子可能选择其他人。所以妹子们的期望值要降低1点。

同时,刚才被抢的男生此时非常得意,因为有妹子来抢他,于是他的期望值提高了1点(就是同妹子们降低的期望值相同)。

于是期望值变成这样(当然,不参与刚才匹配过程的人期望值不变)

==============继续为女2找对象=============

(此时女1—男3)

女2选择了男1

男1还没有被配对

女2找对象成功!

==============为女2找对象成功=============

==============为女3找对象===============

(此时女1—男3,女2-男1)

女3没有可以配对的男生……

女3找对象失败

==============为女3找对象失败============

此轮只有女3参与匹配

此时应该为女3降低期望值

降低期望值1的时候,女3-男3可以配对,所以女3降低期望值1

==============继续为女3找对象============

(此时女1—男3, 女2-男1)

女3相中了男3

此时男3已经有主女1,于是女1尝试换人

女1选择男1

而男1也已经有主女2,女2尝试换人

前面说过,每一轮匹配每个男生只被匹配一次

所以女2换人失败

女3找对象再次失败

==============为女3找对象失败============

这一轮匹配相关人员:女1,女2,女3,男1,男3

此时,只要女2降低1点期望值,就能换到男2

(前面提过 只要任意一个女生能换到任意一个没有被选择过的男生所需要降低的最小值)

我们把相应人员期望值改变一下

==============还是为女3找对象============

(此时女1—男3, 女2-男1)

女3选择了男3

男3有主女1,女1尝试换人

女1换到了男1

男1已经有主女2,女2尝试换人

女2换人男2

男2无主,匹配成功!!!

==============为女3找对象成功=============

匹配成功!!!撒花~~

到此匹配全部结束

此时

女1-男1,女2-男2,女3-男3

好感度和为最大:9

虽然不停换人的过程听起来很麻烦,但其实整个是个递归的过程,实现起来比较简单。比较复杂的部分就是期望值的改变,但是可以在递归匹配的过程中顺带求出来。

模板(带详细注释)(入门题:HDU2255(复杂度应该是O(N^3)

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4
  5 using namespace std;
  6 const int MAXN = 305;
  7 const int INF = 0x3f3f3f3f;
  8
  9 int love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
 10 int ex_girl[MAXN];      // 每个妹子的期望值
 11 int ex_boy[MAXN];       // 每个男生的期望值
 12 bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
 13 bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
 14 int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
 15 int slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
 16
 17 int N;
 18
 19
 20 bool dfs(int girl)
 21 {
 22     vis_girl[girl] = true;
 23
 24     for (int boy = 0; boy < N; ++boy) {
 25
 26         if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
 27
 28         int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
 29
 30         if (gap == 0) {  // 如果符合要求
 31             vis_boy[boy] = true;
 32             if (match[boy] == -1 || dfs( match[boy] )) {    // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
 33                 match[boy] = girl;
 34                 return true;
 35             }
 36         } else {
 37             slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
 38         }
 39     }
 40
 41     return false;
 42 }
 43
 44 int KM()
 45 {
 46     memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
 47     memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0
 48
 49     // 每个女生的初始期望值是与她相连的男生最大的好感度
 50     for (int i = 0; i < N; ++i) {
 51         ex_girl[i] = love[i][0];
 52         for (int j = 1; j < N; ++j) {
 53             ex_girl[i] = max(ex_girl[i], love[i][j]);
 54         }
 55     }
 56
 57     // 尝试为每一个女生解决归宿问题
 58     for (int i = 0; i < N; ++i) {
 59
 60         fill(slack, slack + N, INF);    // 因为要取最小值 初始化为无穷大
 61
 62         while (1) {
 63             // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
 64
 65             // 记录每轮匹配中男生女生是否被尝试匹配过
 66             memset(vis_girl, false, sizeof vis_girl);
 67             memset(vis_boy, false, sizeof vis_boy);
 68
 69             if (dfs(i)) break;  // 找到归宿 退出
 70
 71             // 如果不能找到 就降低期望值
 72             // 最小可降低的期望值
 73             int d = INF;
 74             for (int j = 0; j < N; ++j)
 75                 if (!vis_boy[j]) d = min(d, slack[j]);
 76
 77             for (int j = 0; j < N; ++j) {
 78                 // 所有访问过的女生降低期望值
 79                 if (vis_girl[j]) ex_girl[j] -= d;
 80
 81                 // 所有访问过的男生增加期望值
 82                 if (vis_boy[j]) ex_boy[j] += d;
 83                 // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
 84                 else slack[j] -= d;
 85             }
 86         }
 87     }
 88
 89     // 匹配完成 求出所有配对的好感度的和
 90     int res = 0;
 91     for (int i = 0; i < N; ++i)
 92         res += love[ match[i] ][i];
 93
 94     return res;
 95 }
 96
 97 int main()
 98 {
 99     while (~scanf("%d", &N)) {
100
101         for (int i = 0; i < N; ++i)
102             for (int j = 0; j < N; ++j)
103                 scanf("%d", &love[i][j]);
104
105         printf("%d\n", KM());
106     }
107     return 0;
108 }

原文地址:https://www.cnblogs.com/ymzjj/p/10004555.html

时间: 2024-10-14 09:28:14

二分图最大权值匹配 KM算法 模板的相关文章

HDU2255-奔小康赚大钱-二分图最大权值匹配-KM算法

二分图最大权值匹配问题.用KM算法. 最小权值的时候把权值设置成相反数 1 /*--------------------------------------------------------------------------------------*/ 2 3 #include <algorithm> 4 #include <iostream> 5 #include <cstring> 6 #include <ctype.h> 7 #include &l

【二分图最大权完美匹配】【KM算法模板】【转】

[文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] 这里就贴一下模板代码..2333... 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6

带权二分图的最大权匹配 KM算法模版

带权二分图的最大权匹配 KM算法模版 下面是kuangbin大神的模版,已通过西电oj1048的测试 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set

二分图&#39;最佳匹配&#39; KM算法

讲得很清楚的博客  推荐! 点我?? 附上一模板题 // hdu 2255(求最大权和) 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int INF = 0x3f3f3f3f; 5 const int MAXN = 300+5; 6 7 int n; 8 int w[MAXN][MAXN];// 权值数组 9 int cx[MAXN], cy[MAXN];// "标杆&qu

POJ 2195 二分图最小权匹配KM算法

本来是打算昨天晚上写的, 昨天网速渣的连CSDN都进不去,没办法 只能现在来写了 先写写对KM算法的理解,KM算法是对每个点设置一个顶标,只有当边长等于两边点的顶标之和的时候才进行增广,这样就能保证得到的一定是最大权匹配. 如果找不到匹配的时候就对交替路中X集合的顶标减少一个d Y集合的顶标增加一个d. 这样两个点都在交替路中的时候x[i]+y[i]的和不边 X在 Y不在的时候x[i]+y[i]减少,可能就会为图增加一对匹配. X不在Y在的时候x[i]+y[i]增加, 原来不在现在依然不在其中.

训练指南 UVALive - 4043(二分图匹配 + KM算法)

layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图匹配 - 图论 - 训练指南 Ants UVALive - 4043 题意 给你n个白点和n个黑点的平面坐标,要求用n条不相交的线连起来,每条线段连一个白点和黑点,每个点连一条线,也就是匹配.让你输出第i个白点所对应的黑点. 思路 二分图完美匹配问题.但是题目

POJ 2195 Going Home 【二分图最小权值匹配】

传送门:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26151   Accepted: 13117 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit st

hdu 1853 Cyclic Tour 最大权值匹配 全部点连成环的最小边权和

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1904    Accepted Submission(s): 951 Problem Description There are N cities in our c

hdu 1853 Cyclic Tour 最大权值匹配 所有点连成环的最小边权和

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1904    Accepted Submission(s): 951 Problem Description There are N cities in our c