匹配算法告诉你为什么要找女(男)朋友一定要主动?
Posted 陆嵩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了匹配算法告诉你为什么要找女(男)朋友一定要主动?相关的知识,希望对你有一定的参考价值。
稳定匹配:该如何给男孩女孩们配对?
纯文字描述稳定匹配(stable matching)。
定义
有这样一个问题,大概意思说是给一群男的和一群女的配对,每个男的对所有女的喜欢程度都有一个排序,所有女的对所有男的喜欢程度也有一个排序,男女人数相等。
我们给一个不稳定对(blocking pair)的定义。假设小明的女朋友更喜欢小东,比起小东自己的女朋友,小东更喜欢小明的女朋友,这时候,(小明的女朋友,小东)就是一个不稳定对,因为他们比起现有的匹配,更喜欢对方,就很容易搞在一起。
一个匹配是稳定匹配,当且仅当这当中不存在任何不稳定对。
事实上,自由的交易不会导致稳定的婚姻。(会出现环)
算法:延迟接受(盖尔沙普利算法)
有一个简单的想法是,对于约会的配对,大家都去追自己最心仪的女生。而这个女生面对几位追求者,要立刻做个决定。被拒绝的男生们调整一下心情,再去追求心中的 No. 2。重复这个过程。
这样做法有一个严重的问题:当你被你的 No.1 拒绝后,再去追求你的 No.2 的时候,你心中的 No.2 可能已经在第一轮中选择了其他人。
但坑爹的是,有可能你正是你心中 No.2 心中的 No.1,但是她并不知道。所以她在第一轮中,因为没有被你追求,而屈就他人。比及你在第一轮中表白失败,再去找你的 No.2 时,已然晚矣。这时,其实就产生了不稳定的匹配。
那么,有什么方法可以产生稳定的匹配吗?
有一种算法,叫延迟接受算法,可以产生稳定的匹配。它的基本过程如下:
- 第一轮所有的男的都向他们心中的 No.1 示爱。
- 当收到男孩子的表白后,收到了两个以上的表白需要做出自己的选择,mark 一个自己最喜欢的(mark 不代表最终选择,先 hold 住的意思),而拒绝其他人。
- 在第二轮中,第一轮被拒绝的男生再向心中的 No.2 示爱。被示爱的女孩子们,还是 hold 住手中最好的 offer,而把其他拒绝掉。
- ……
- 不断重复如上过程,直到男孩无爱可示。
一个简单的观测是,在这个一轮一轮迭代的过程当中,女孩子的示爱对象会越来令自己满意,而男孩子示爱的对象会是越来越不满意的。
可以看得出来,这个算法必然会终止的,因为每个每个男性的示爱对象是有限的。
这个算法最后的结果一定是男女一一配对。
延迟接受算法产生了稳定的匹配。
我们用文字简单说明一下这一点。简单反正。假如(小明,小明女朋友)、(小东,小东女朋友)是配对结果,且(小明,小东女朋友)是一个不稳定对。
因为小东女朋友更喜欢小明,却和小东在一起了,说明了,小明没和小东女朋友表白过。然而,小明更喜欢小东女朋友,却和小明女朋友一起了,说明他曾经和小东女朋友表白且被拒绝。小明即和小东女朋友表白过,又没和小东女朋友表白过,矛盾。
越主动配偶越好
定义: 如果存在一个稳定匹配中男性
m
m
m 和女性
w
w
w 匹配在一起, 则称女性
w
w
w 是男性
m
m
m 的正当配偶。
一个匹配是稳定匹配,并且所有男性分到的配偶都是最佳的正当配偶,那么称这个匹配是男性最优。
事实上,上面的延迟接受算法产生的匹配一定是男性最优的。我们可以用文字来简单说明一下这点。还是用反证法。
假设延迟算法得到的匹配 1 不是男性最优的匹配,那么必然存在一个稳定匹配 2,存在某个男性,这个男性在匹配 2 中的配偶比匹配 1中的好。我们不妨假设,在算法滚动当中,第一个被更好的正当配偶拒绝的男性为 A。它在匹配 1 中的配偶是 a。假定 A 在匹配 2 中的配偶是 b(即匹配 1 算法中,拒绝 A 的就是 b)。假定 b 在拒绝 A 的时候手中的 配偶是 B,B 在匹配 2 中的正当配偶是 c。
-
算法过程告诉我们,b 更喜欢 B 比起 A。
-
B 也更喜欢 b 比起 c。否则,如果他更喜欢 c 的话,他在被 b hold 住(即 A 选择 b 被拒)之前,必然选择 c 被拒绝过。这个和 A 是第一个被更好的正当配偶拒绝的男性矛盾。
以上两点告诉我们,b 更喜欢 B 比起 A,B 也更喜欢 b 比起 c,那么匹配 2 就不是稳定匹配,这和开始的假设,匹配 2 是个稳定匹配矛盾。
由此推出了,延迟接受算法产生的匹配一定是男性最优的。
类似地,可以证明这个算法中,女性一定分配到的是最差的正当配偶。
代码实现
直接抄一下别人的代码。
class Solution {
public:
vector<vector<int>> stableMatching(vector<vector<int>> man_list, vector<vector<int>> woman_list) {
int man_num = man_list.size();
int woman_num = woman_list.size();
// 男女数量不同,无法完美匹配
if (man_num != woman_num) return {};
int n = man_num;
// 将女性喜好列表的索引和数据置反,方便处理
vector<vector<int>> inverse_womanlist;
for (int i = 0; i < n; ++i) {
vector<int> prefer(n, -1);
for (int j = 0; j < n; ++j) {
prefer[woman_list[i][j]] = j;
}
inverse_womanlist.push_back(prefer);
}
// 记录最终的匹配结果
vector<vector<int>> S = {};
// 记录单身男性
queue<int> free_man;
for (int i = 0; i < n; ++i) {
free_man.push(i);
}
// husband[w] = m:女性 w 的伴侣是 m
vector<int> husband(n, -1);
// 为每个男性维护一个指针(索引),记录喜爱列表中下一个求婚的女性索引
vector<int> man_pointer(n, 0);
// G-S算法主体
while (!free_man.empty()) {
int m = free_man.front();
int w = man_list[m][man_pointer[m]];
// 男方求婚指针向前
man_pointer[m]++;
// 女方无配偶
if (husband[w] == -1) {
S.push_back({m,w});
free_man.pop();
husband[w] = m;
}
// 男人m比当前配偶更有吸引力
else if (inverse_womanlist[w][husband[w]] > inverse_womanlist[w][m]) {
// 找到 S 中原来关于 w 的一对
int index;
for (index = 0; index < S.size(); index++) {
if (S[index][1] == w) break;
}
int old_m = S[index][0];
// 从 S 中删除 m'-w
S.erase(S.begin() + index);
// 在 S 中添加 m -w
S.push_back({m, w});
free_man.pop();
// w 原来的配偶变为单身汉
free_man.push(old_m);
husband[w] = m;
}
else {
// w 拒绝 m
}
}
return S;
}
};
int main() {
// 索引代表男性编号(0,1,2),数组代表喜好女性的列表
vector<vector<int>> manlist = {{0,1,2},
{1,0,2},
{0,1,2}};
// 索引代表女性编号(0,1,2),数组代表喜好男性的列表
vector<vector<int>> womanlist = {{1,2,0},
{0,1,2},
{0,1,2}};
Solution test;
vector<vector<int>> result;
result = test.stableMatching(manlist, womanlist);
for (int i = 0; i < manlist.size(); ++i) {
cout << result[i][0] << " - " << result[i][1] << endl;
}
return 0;
}
对于恋爱的启示
这个稳定匹配的算法,本质上就是自由的男同胞们不断地从高到底向女性们求爱,女性们总是在手里保留一个最佳 offer。在这个过程中,男的不断地被拒绝,而女的似乎掌控着更多的自主权,总是挑选一个最好的。
因为男的是被选择人,女的是选择人,从这个层面上看,似乎这个算法是对女方是更有利的。然而,出乎意料的是。最后的匹配的结果确是,在稳定匹配中,男生们选到了最佳选择,而女生们选到了最差的选择。
由此可见,找对象嘛,主动比被动最后得到的结果会更好。这也解释了为什么主动的“渣男”们总能找到高质量的女生的原因,而想我这样的老实人,注孤生。
既然主动表达爱意的一方总是占据上风,So,Boys and Girls,主动一点吧。
以上是关于匹配算法告诉你为什么要找女(男)朋友一定要主动?的主要内容,如果未能解决你的问题,请参考以下文章