【算法笔记】稳定婚姻匹配问题-GS算法

什么是稳定(婚姻)匹配问题

这里是百度百科。有N男N女,均为异性恋,每个人都对异性有好感度排序。如何将他们两两配对,才能尽可能使结果令每个人都满意。

当然也有N男M女、多对一的情况,这里先不讨论(网上有些大牛写了论文)。

 

处理方案

被广泛认可的算法是由美国数学家 David Gale 和 Lloyd Shapley 于1962年发明的 Gale-Shapley算法,简称GS算法。GS算法的思路如下:

先给N男N女从0~N-1分别编号,然后要求每个人写出他们对异性的好感度排序。为了方便,这里N取4.比如0号男最喜欢3号女,其次是0号女,再次是1号女,最后是2号女,则0号男给出的排序为3 0 1 2.

下图中展示了好感排序情况(随机给出):

GS_data

第一轮,先让每个男性向他们最喜欢的女性表白(也可以女性表白男性,同理)。例如0号男会先向3号女表白。如果一个女性同时收到了两个表白,她会选择接受自己最喜欢的那个男性。如3号女同时收到0号和2号的表白,接受0号。
第一次匹配结束后的情况:
0号男-3号女    1号男-0号女    3号男-1号女

第二轮,由于第一轮时只有2号男落单(惨),这次2号男选择向自己第二喜欢的1号女表白。1号女接到表白后,会比较现任对象(3号男)和2号男,发现自己更喜欢2号男,于是与3号男分手,投入2号男的怀抱。
第二次匹配结束后的情况:
0号男-3号女    1号男-0号女    2号男-1号女

第三轮,3号男向自己第二喜欢的0号女表白,0号女比较现任配偶(1号男)和3号男,觉得自己还是更喜欢现任配偶,3号男被残忍拒绝。这次匹配关系没有发生变化。

第四轮,3号男向自己第三喜欢的2号女表白。2号女还没有收到过表白,直接接受。
第四次匹配结束后的情况:
0号男-3号女    1号男-0号女    2号男-1号女    3号男-2号女

此时每个人都找到了配偶,匹配结束。

简单总结一下,每一轮开始时:
①没有配偶的男性选择自己好感度最高而且没表白过的女性表白。
②接到表白的女性比较现任配偶和新追求者的好感度,选择与好感度更高的男性重新匹配。

 

GS算法的局限性

从算法过程容易看出,按照“男性表白女性”的策略对女性更有利,因为女性的配偶质量会不断提升,而男性的配偶质量会不断变差。相反则对男性有利。不同的表白策略得出的匹配结果很可能是不同的。

GS算法能否保证每个人都有对象

假设有一个男性A落单,由于男女人数相等,则必定还有一个女性B落单。
根据算法,B是被动接受表白,只要收到过一次表白,B就不可能落单。
而如果A没有配偶,他会一直表白下去,将N个女性全部表白一遍。这个过程中B一定会收到表白,两人匹配。

上述内容同时可以证明,该算法会在有限次运算后结束(运算次数小于n*n)。

GS算法的结果是否稳定

“稳定”是指:算法结束后,如果再进行一轮表白,一定不会出现男女双方的选择都更优的情况。
这一点容易证明。根据算法局限性,再进行表白,男性对新配偶的好感度只会下降。

假设男性A与女性B本应匹配(也就是说现在两个人分别有自己的配偶,但是从好感度角度来说,他们都更希望彼此形成新的匹配),可以分两种情况讨论:
1.男性A曾对女性B表白,但此时两人没有匹配,说明女性B后来遇到了好感度更高的男性,假设不成立。
2.男性A不曾对女性B表白,说明男性A的配偶好感度排在女性B前面,假设不成立。

 

代码实现

 1     #include<cstdio>
 2     #include<algorithm>
 3     #include<cmath>
 4     #include<iostream>
 5     #include<cstring>
 6     #include<string>
 7     using namespace std;
 8     const int MAXN = 0 + 5;
 9     int Num,nowMatch;
10     int Match_A[MAXN], Match_B[MAXN], Preference_A[MAXN][MAXN], Preference_B[MAXN][MAXN], Now[MAXN];
11     //Match数组记录匹配情况,Preference[i][1..n]记录好感排序
12     inline void init()
13     {//读入、预处理
14       scanf("%d", &Num);
15       for (int i = 0; i < Num; ++i)
16         for (int j = 0; j < Num; ++j)
17           scanf("%d", &Preference_A[i][j]);
18       for (int i = 0; i < Num; ++i)
19         for (int j = 0; j < Num; ++j)
20           scanf("%d", &Preference_B[i][j]);
21       for (int i = 0; i < Num; ++i)
22         Match_A[i] = -1, Match_B[i] = -1;
23     }
24     bool Compare(int a, int b, int Obj)
25     {//比较追求当前的B[i]的两个人在B[i]处的好感排序
26       int index_a = -1, index_b = -1;
27       for (int i = 0; i < Num; ++i)
28       {
29         if (Preference_B[Obj][i] == a)
30           index_a = i;
31         else if (Preference_B[Obj][i] == b)
32           index_b = i;
33       }
34       if (index_a < index_b) return true;
35       return false;
36     }
37     bool AllMatch()
38     {//判断是否完成匹配
39       int count = 0;
40       for (int i = 0; i < Num; ++i)
41         if (Match_A[i] != -1)
42           count++;
43       if (count < Num) return false;
44       return true;
45     }
46     void Gale_Shapley()
47     {
48       while (! AllMatch())
49       {//算法会在所有人完成匹配后终止
50         for (int i = 0; i < Num; i ++)
51         {
52           if (Match_A[i] != -1) continue;
53           nowMatch = Match_B[Preference_A[i][Now[i]]];
54           //nowMatch是A[i]想要表白的B[i]目前的对象,没有则为-1
55           if (nowMatch == -1 || Compare(i, nowMatch, Preference_A[i][Now[i]]))
56           {//如果B[i]没有对象,或者B[i]对A[i]更有好感,则A[i]和B[i]匹配
57             Match_A[i] = Preference_A[i][Now[i]];
58             Match_A[nowMatch] = -1;
59             Match_B[Preference_A[i][Now[i]]] = i;
60           }
61           Now[i] ++;
62         }
63       }
64     }
65     inline void Output()
66     {
67       for (int i = 0; i < Num; ++i)
68       {
69         printf("A-%d is matched to B-%d\n", i, Match_A[i]);
70       }
71     }
72     int main()
73     {
74       init();
75       Gale_Shapley();
76       Output();
77       return 0;
78     }
GS code

 

测试一下最初给的那组数据

example

 

应用

虽然算法解决的问题是“稳定婚姻匹配”,但是真的按照这个算法来选对象岂不太简单粗暴了…不过这好歹还是对象包分配
GS算法可以用于解决工作岗位的分配问题,例如某公司有n个岗位,m(m>=n)人竞争,可以根据公司和应聘者对彼此的好感度排序,利用算法算出最合适的人选。

 

漫谈

如果把上文中的人视为点,好感关系视为线,就构成了一个二分图匹配问题。问题就可以转化为:根据已有的好感度排序,如何连线才能使得左右两侧的点一一相连,且连线结果尽量令人满意。

匹配成功后的结果如图所示,是一个一一映射:

如果把这个问题削弱一下,条件可以改为:每个人都对M(M<=N)名异性有好感,这种好感不分大小。如何使尽量多对互有好感的人相匹配。这个问题称作二分图最大匹配问题,可以用匈牙利算法求解。

posted @ 2020-08-10 09:51  Kamigen  阅读(2053)  评论(1编辑  收藏  举报

很高兴见到你,祝你旅途愉快!