下面的引用《程序员》杂志上的一篇文章,来说明什么是稳定婚姻问题和Gale-Shapley算法。

网址:http://www.programmer.com.cn/12001/

什么是算法?每当有人问作者这样的问题时,他总会引用这个例子:假如你是一个媒人,有若干个单身男子登门求助,还有同样多的单身女子也前来征婚。如果你已经知道这些女孩儿在每个男孩儿心目中的排名,以及男孩儿们在每个女孩儿心中的排名,你应该怎样为他们牵线配对呢?

最好的配对方案当然是,每个人的另一半正好都是自己的“第一选择”。这虽然很完美,但绝大多数情况下都不可能实现。比方说,男1号最喜欢的是女1号,而女1号的最爱不是男1号,这两个人的最佳选择就不可能被同时满足。如果好几个男孩儿最喜欢的都是同一个女孩儿,这几个男孩儿的首选也不会同时得到满足。当这种最为理想的配对方案无法实现时,怎样的配对方案才能令人满意呢?

其实,找的对象太完美不见得是好事儿,和谐才是婚姻的关键。如果男1号和女1号各有各的对象,但男1号觉得,比起自己现在的,女1号更好一些;女1号也发现,在自己心目中,男1号的排名比现男友更靠前。这样一来,这两人就可能抛弃各自现在的对象——如果出现了这种情况,我们就说婚姻搭配是不稳定的。作为一个红娘,你深知,对象介绍得不好没关系,就怕婚姻关系不稳定。给客户牵线配对时,虽然不能让每个人都得到最满意的,但搭配必须得稳定。换句话说,对于每一个人,在他心目中比他当前伴侣更好的异性,都不会认为他也是一个更好的选择。现在,我们的问题是:稳定的婚姻搭配总是存在吗?应该怎样寻找?

一次失败的尝试

为了便于分析,我们下面做一些约定。我们用字母A、B、C对男性进行编号,用数字1、2、3对女性进行编号。我们把所有男性从上到下列在左侧,括号里的数字表示每个人心目中对所有女性的排名;再把所有女性列在右侧,用括号里的字母表示她们对男性的偏好。图1所示的就是2男2女的一种情形,每个男的都更喜欢女1号,但女1号更喜欢男B,女2号更喜欢男A。若按A-1、B-2进行搭配,则男B和女1都更喜欢对方一些,这样的婚姻搭配就是不稳定的。但若换一种搭配方案(如图2),这样的搭配就是稳定的了

图1 一个不稳定的婚姻搭配图

可能很多人会立即想到一种寻找稳定婚姻搭配的策略:不断修补当前搭配方案。如果两个人互相都觉得对方比自己当前的伴侣更好,就让这两个人成为一对,剩下被甩的那两个人组成一对。

图2 一个稳定的婚姻搭配

如果还有想要私奔的男女对,就继续按照他们的愿望对换情侣,直到最终消除所有的不稳定组合。容易看出,应用这种“修补策略”所得到的最终结果一定满足稳定性,但这种策略的问题在于,它不一定存在“最终结果”。事实上,按照上述方法反复调整搭配方案,最终可能会陷入一个死循环,因此该策略甚至不能保证得出一个确定的方案来,如图3所示。

图3 应用“修补策略”可能会产生死循环

Gale-Shapley算法

1962年,美国数学家David Gale和Lloyd Shapley发明了一种寻找稳定婚姻的策略。不管男女各有多少人,也不管他们的偏好如何,应用这种策略后总能得到一个稳定的搭配。换句话说,他们证明了稳定的婚姻搭配总是存在的。有趣的是,这种策略反映了现实生活中的很多真实情况。

在这种策略中,男孩儿将一轮一轮地去追求他中意的女子,女子可以选择接受或者拒绝他的追求者。第一轮,每个男孩儿都选择自己名单上排在首位的女孩儿,并向她表白。此时,一个女孩儿可能面对的情况有三种:没有人跟她表白,只有一个人跟她表白,有不止一个人跟她表白。在第一种情况下,这个女孩儿什么都不用做,只需要继续等待;在第二种情况下,接受那个人的表白,答应暂时和他做情侣;在第三种情况下,从所有追求者中选择自己最中意的那一位,答应和他暂时做情侣,并拒绝所有其他追求者。

第一轮结束后,有些男孩儿已经有女朋友了,有些男孩儿仍然是单身。在第二轮追女行动中,每个单身男孩儿都从所有还没拒绝过他的女孩儿中选出自己最中意的那一个,并向她表白,不管她现在是否是单身。和第一轮一样,女孩儿们需要从表白者中选择最中意的一位,拒绝其他追求者。注意,如果这个女孩儿已经有男朋友了,当她遇到了更好的追求者时,她必须拒绝掉现在的男友,投向新的追求者的怀抱。这样,一些单身男孩儿将会得到女友,那些已经有了女友的人也可能重新变成光棍。在以后的每一轮中,单身男孩儿继续追求列表中的下一个女孩儿,女孩儿则从包括现男友在内的所有追求者中选择最好的一个,并对其他人说不。这样一轮一轮地进行下去,直到某个时候所有人都不再单身,下一轮将不会有任何新的表白发生,整个过程自动结束。此时的婚姻搭配就一定是稳定的了。

这个策略会不会像之前的修补法一样,出现永远也无法终止的情况呢?不会。下面我们将说明,随着轮数的增加,总有一个时候所有人都能配对。由于在每一轮中,至少会有一个男孩儿向某个女孩儿告白,因此总的告白次数将随着轮数的增加而增加。倘若整个流程一直没有因所有人都配上对了而结束,最终必然会出现某个男孩儿追遍了所有女孩儿的情况。而一个女孩儿只要被人追过一次,以后就不可能再单身了。既然所有女孩儿都被这个男孩儿追过,就说明所有女孩儿现在都不是单身,也就是说此时所有人都已配对。

图4 应用上述策略,三轮之后将得出稳定的婚姻搭配

接下来,我们还需要证明,这样得出的配对方案确实是稳定的。首先注意到,随着轮数的增加,一个男孩儿追求的对象总是越来越糟,而一个女孩儿的男友只可能变得越来越好。假设男A和女1各自有各自的对象,但比起现在的对象,男A更喜欢女1。因此,男A之前肯定已经跟女1表白过。既然女1最后没有跟男A在一起,说明女1拒绝了男A,也就是说她有了比男A更好的男孩儿。这就证明了,两个人虽然不是一对,但都觉得对方比自己现在的伴侣好,这样的情况绝不可能发生。

我们把用来解决某种问题的一个策略,或者说一个方案,或者说一个处理过程,或者说一系列操作规则,或者更贴切地说,一套计算方法,叫做“算法”。上面这个用来寻找稳定婚姻的策略就叫做“Gale-Shapley算法”,有些人也管它叫“延迟认可算法”。

Gale-Shapley算法的意义和应用

每个算法都有它的实际意义,能给我们带来很多启发。Gale-Shapley算法最大的意义就在于,作为一个为这些男女牵线的媒人,你并不需要亲自计算稳定婚姻匹配,甚至根本不需要了解每个人的偏好,只需要按照这个算法组织一个男女配对活动就可以了。你需要做的仅仅是把算法流程当作游戏规则告诉大家,游戏结束后会自动得到一个大家都满意的婚姻匹配。整个算法可以简单地描述为:每个人都去做自己想做的事情。对于男性来说,从最喜欢的女孩儿开始追起是顺理成章的事;对于女性来说,不断选择最好的男孩儿也正好符合她的利益。因此,大家会自动遵守游戏规则,不用担心有人虚报自己的偏好。

历史上,这样的“配对游戏”还真有过实际应用,并且更有意思的是,这个算法的应用居然比算法本身的提出还早10年。早在1952年,美国就开始用这种办法给医学院的学生安排工作,这被称之为“全国住院医师配对项目”。配对的基本流程就是,各医院从尚未拒绝这一职位的医学院学生中选出最佳人选并发送聘用通知,当学生收到来自各医院的聘用通知后,系统会根据他所填写的意愿表自动将其分配到意愿最高的职位,并拒绝掉其他的职位。如此反复,直到每个学生都分配到了工作。那时人们并不知道这样的流程可以保证工作分配的稳定性,只是凭直觉认为这是很合理的。直到10年之后,Gale和Shapley才系统地研究了这个流程,提出了稳定婚姻问题,并证明了这个算法的正确性。

这个算法还有很多有趣的性质。比如说,大家可能会想,这种男追女女拒男的方案对男性更有利还是对女性更有利呢?答案是,这种方案对男性更有利。事实上,稳定婚姻搭配往往不止一种,然而上述算法的结果可以保证,每一位男性得到的伴侣都是所有可能的稳定婚姻搭配方案中最理想的,同时每一位女性得到的伴侣都是所有可能的稳定婚姻搭配方案中最差的。受篇幅限制,我们略去证明的过程。

这个算法会有一些潜在的问题。刚才我们已经说了,对于每位女性来说,得到的结果都是所有可能的稳定搭配中最差的一种。此时,倘若有某位女性知道所有其他人的偏好列表,经过精心计算,她有可能发现,故意拒绝掉本不该拒绝的人(暂时保留一个较差的人在身边),或许有机会等来更好的结果。因而,在实际生活中应用这种算法,不得不考虑一些可能的欺诈与博弈。

这个算法还有一些局限。例如,它无法处理2n个人不分男女的稳定搭配问题。一个简单的应用场景便是宿舍分配问题:假设每个宿舍住两个人,已知2n个学生中每一个学生对其余2n-1个学生的偏好评价,如何寻找一个稳定的宿舍分配?此时,Gale-Shapley算法就不再有用武之地了。而事实上,宿舍分配问题中很可能根本就不存在稳定的搭配。例如,有A、B、C、D四个人,其中A把B排在第一,B把C排在第一,C把A排在第一,而且他们三人都把D排在最后。容易看出,此时一定不存在稳定的宿舍分配方案。倘若A、D同宿舍,B、C同宿舍,那么C会认为A是更好的室友(因为C把A排在了第一),同时A会认为C是更好的室友(因为他把D排在了最后)。同理,B、D同宿舍或者C、D同宿舍也都是不行的,因而稳定的宿舍分配是不存在的。此时,重新定义宿舍分配的优劣性便是一个更为基本的问题。

稳定婚姻问题还有很多其他的变种,有些问题甚至是NP完全问题,至今仍然没有(也不大可能有)一种有效的算法。在图论、算法和博弈论中,这都是非常有趣的话题。

作者顾森,网名Matrix67,北京大学中文系应用语言学专业学生,数学爱好者。2005年开办数学博客http://www.matrix67.com,至今已积累上千篇文章,已有上万人订阅。

本文选自《程序员》杂志2012年06期

下面是wikipida上给这个算法的描述:

  1. function stableMatching {
  2. Initialize all m ∈ M and w ∈ W to free
  3. while ∃ free man m who still has a woman w to propose to {
  4. w = highest ranked woman to whom m has not yet proposed
  5. if w is free
  6. (m, w) become engaged
  7. else some pair (m', w) already exists
  8. if w prefers m to m'
  9. (m, w) become engaged
  10. m' becomes free
  11. else
  12. (m', w) remain engaged
  13. }
  14. }

我根据上面的思路,对这个算法进行了实现,使用了上文中的例子,得出了相同的结论

  1. /*
  2. * main.c
  3. *
  4. * Created on: 2015年3月25日
  5. * Author: wlj
  6. */
  7. #include<stdio.h>
  8. #include<stdlib.h>
  9. #define N 4
  10. typedef struct _W_INFO
  11. {
  12. int rank; //在这个男孩心中,这个女孩的排名,数值越大表示越好
  13. int status; //这个女的是否表白过
  14. } W_INFO;
  15. typedef struct _MAN
  16. {
  17. int status; //表示现在是否单身
  18. W_INFO w_info[N]; //用来存储所有女孩的信息
  19. int lover; //如果表白成功,对象的id(只有status状态为1时,这个值才有意义)
  20. } MAN;
  21. typedef struct _WOMAN
  22. {
  23. int status; //表示这个女孩是否单身
  24. int rank[N]; //用来存储所有男孩的排名
  25. int lover;
  26. } WOMAN;
  27. MAN man[N];
  28. WOMAN woman[N];
  29. int ExistFree()
  30. {
  31. int m;
  32. for (m = 0; m < N; m++)
  33. {
  34. if (man[m].status == 0)
  35. {
  36. return 1;
  37. }
  38. }
  39. return 0;
  40. }
  41. int SelectWoman(int m)
  42. {
  43. int w;
  44. W_INFO woman;
  45. int best_rank = -1;
  46. int best_id = -1;
  47. //为男孩m找出一个最好的,且未表白过的女孩
  48. for (w = 0; w < N; w++)
  49. {
  50. woman = man[m].w_info[w];
  51. if (woman.status == 0) //如果这个女的是没有表白过
  52. {
  53. if (woman.rank > best_rank)
  54. {
  55. best_rank = woman.rank;
  56. best_id = w;
  57. }
  58. }
  59. }
  60. return best_id;
  61. }
  62. //男孩m向女孩w表白
  63. void Propose(int m, int w)
  64. {
  65. int lover;
  66. /*
  67. * 男孩m向女孩w表白
  68. *
  69. */
  70. //如果这个女孩是单身
  71. if (woman[w].status == 0)
  72. {
  73. //女孩w告别单身,找到lover
  74. woman[w].status = 1;
  75. woman[w].lover = m;
  76. //男孩m告别单身,找到lover
  77. man[m].status = 1;
  78. man[m].lover = w;
  79. }
  80. else //如果这个女孩有男友
  81. {
  82. //这是这个女孩现在的男友
  83. lover = woman[w].lover;
  84. //如果这个女孩现在的男友没有当前表白的这个好
  85. if (woman[w].rank[lover] < woman[w].rank[m])
  86. {
  87. //更换男友
  88. woman[w].lover = m;
  89. //男孩m告别单身,找到lover
  90. man[m].status = 1;
  91. man[m].lover = w;
  92. //女孩与其前男友分手,前男友变成单身
  93. man[lover].status = 0;
  94. }
  95. else
  96. {
  97. //男孩m被拒绝了
  98. }
  99. }
  100. //男孩m记下,已经向女孩w表白过了
  101. man[m].w_info[w].status = 1;
  102. }
  103. void StableMatching()
  104. {
  105. int m;
  106. int w;
  107. while (ExistFree())
  108. {
  109. for (m = 0; m < N; m++)
  110. {
  111. if (man[m].status == 0)
  112. {
  113. w = SelectWoman(m);
  114. Propose(m, w);
  115. }
  116. }
  117. }
  118. }
  119. void InitData()
  120. {
  121. int m_w[N][N] = { { 1, 2, 4, 3 }, { 1, 3, 4, 2 }, { 4, 1, 3, 2 }, { 1, 4, 2, 3 } };
  122. int w_m[N][N] = { { 4, 1, 2, 3 }, { 4, 3, 2, 1 }, { 4, 3, 1, 2 }, { 3, 4, 1, 2 } };
  123. int i, j;
  124. for (i = 0; i < N; i++)
  125. {
  126. man[i].status = 0;
  127. man[i].lover = -1;
  128. woman[i].lover = -1;
  129. woman[i].status = 0;
  130. for (j = 0; j < N; j++)
  131. {
  132. man[i].w_info[j].rank = m_w[i][j];
  133. man[i].w_info[j].status = 0;
  134. woman[i].rank[j] = w_m[i][j];
  135. }
  136. }
  137. }
  138. void PrintInfo()
  139. {
  140. int i;
  141. char m = 'A';
  142. for (i = 0; i < N; i++)
  143. {
  144. printf("%c <----> %d\n", m, man[i].lover + 1);
  145. m++;
  146. }
  147. }
  148. int main()
  149. {
  150. InitData();
  151. StableMatching();
  152. PrintInfo();
  153. return 0;
  154. }

运行的结果

A <----> 3
B <----> 2
C <----> 1
D <----> 4

还是挺靠谱,结论是在这种假设的下,女孩多半可以找到心仪对象,但男同志多半只能将就,一般不会出现不稳定的情况,与现实的情况基本上是吻合的,也一定程度上验证了人类社会在男女比例适当时候是比较稳定的,显然是明摆的道理,原因是光棍是种不稳定的因素。

Shapley算法总结相关推荐

  1. 稳定婚姻问题:Gale–Shapley算法

    (一)问题的引出 在组合数学.经济学.计算机科学中,稳定婚姻问题(英语:stable marriage problem,简称SMP)又称为稳定配对问题(stable matching problem) ...

  2. 开源火种_火种艾完美的牵线搭桥

    开源火种 人工智能,意见,技术(Artificial Intelligence, Opinion, Technology) "Bored in the house, in the house ...

  3. 男女稳定匹配问题 stable matching

    离散数学课(CSCI 2110)上,讲到一个有趣的问题. 假设有五个男生,五个女生,每个人都在自己心中对五个异性有一定的preference排序,比如: 以上的排序表解读为:男生1最中意女生C,次中意 ...

  4. 关于机器学习模型的可解释性算法!

     模型可解释性汇总 简 介 目前很多机器学习模型可以做出非常好的预测,但是它们并不能很好地解释他们是如何进行预测的,很多数据科学家都很难知晓为什么该算法会得到这样的预测结果.这是非常致命的,因为如果我 ...

  5. 算法证明:女生遇到心动的男人一定要追!

    我来讲恋爱中的博弈,不,我来讲恋爱中的算法,不,我来讲算法!! 有个著名的问题,叫做 stable matching.早年是一个可爱的俄罗斯老头在图论课上教我的,印象非常深刻,拿出来娱乐下大家.因为这 ...

  6. 听听阿里老哥对算法工程师技术学习路线的建议

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要15分钟 Follow小博主,每天更新前沿干货 来源丨https://zhuanlan.zhihu.com/p/192633890 前言 知乎 ...

  7. 【文末福利】图论算法:稳定婚姻问题,如何找到最适合自己的另一半

    什么是算法? >>>> 每当有人问我这样的问题,我总会引用下面这个例子. 假如你是一个媒人,有若干名单身男子登门求助,还有同样多的单身 女子也来征婚.如果你已经知道这些女孩儿在 ...

  8. 图论 —— 稳定婚姻问题与延迟认可算法

    [稳定婚姻问题] 1.集合 M 表示 n 个男性 2.集合 F 表示 n 个女性 3.对于每个人我们都按异性的中意程度给出一份名单(从最中意的到最不中意的) 如果没有 ,f 对 m 比对她的配偶中意的 ...

  9. hdu - 1435 Stable Match 稳定婚姻问题、Gale-Shapley算法模板

    稳定婚姻的描述: 假如你是一个媒人,有若干个单身男子登门求助,还有同样多的单身女子也前来征婚.如果你已经知道这些女孩儿在每个男孩儿心目中的排名,以及男孩儿们在每个女孩儿心中的排名,你应该怎样为他们牵线 ...

  10. 婚恋交友网站比相亲更靠谱!幸福婚姻算法了解一下

    导读:算法真的能帮助你找到灵魂伴侣吗?当你访问OKCupid时,会看到一条带着些许骄傲情绪的标题--"我们用数学为你找到约会对象". 作者:马库斯·杜·索托伊(Marcus du ...

最新文章

  1. 计算机的英语怎么写的英语怎么写,计算机英语怎么写
  2. Mac的移动硬盘不能装载该如何解决?
  3. 英国将迎来史上第二位女首相
  4. 如何提高Google Adsense单价:点击率篇
  5. 解决问题的能力 10倍程序员
  6. 数码管显示实验一 编写程序让8只数码管同时显示零
  7. java 比较器类_java常用类——比较器
  8. golang for range原理(转载)
  9. libjpeg学习2:内存篇
  10. IE7下JSON不能有多余的逗号,IE8下创建IMG节点的BUG
  11. HTML5 postMessage解决跨域|跨窗口通信
  12. 集成电路模拟版图入门-版图基础学习笔记(三)
  13. aspectjweaver和aspectjrt的作用?(作用、说明、案例)
  14. allure的安装使用以及报告的生成
  15. 201771010112罗松《面向对象程序设计(java)》第十二周学习总结
  16. 这五个数据分析师技巧你一定要知道!
  17. Android打开自启动设置页面
  18. [转]Kaldi命令词识别
  19. java创建tensorfly对象,Tensorflow对象检测自定义数据集
  20. JVM面试题附带答案

热门文章

  1. SBI集团“逆市”入股玖富,背后意味着什么?|一点财经
  2. 数据库如何增加表中字段
  3. vue调整图标的大小_Vuetify图标大小
  4. CAD/CAM技术的现状分析
  5. python随机森林回归_机器学习:Python实现随机森林回归
  6. python随机森林回归数据实战
  7. 关于NoSql的理解,键值数据库,文档数据库,列式存储数据库,图形数据库
  8. Realtek网卡如何识别具体型号是8111B/8111C/8111D还是8111E
  9. bat批处理脚本执行过程中,Windows运行窗口中出现中文乱码
  10. 如何利用计算机截屏快捷键,电脑怎么截图 电脑选区域截图怎么截 电脑截图快捷键是什么...