稳定婚姻问题

本文介绍的是婚姻匹配的问题

算法问题及介绍

首先贴上一份matrix67大神的博客
如何寻找稳定的婚姻搭配

需要解决的问题

每个男生需要和每一个女生结婚,每一个男生对每一个女生都有一个爱慕程度的排序,同样的每个女生对每一个男生都有一个爱慕的排序。
我们需要找到一个完美匹配,使得匹配的男生和女生有相对较优的匹配结果。不会出现男生A女生1已经匹配好了,男生B女生2已经匹配好了但是男生A心目中女生2的优先级更高,并且女生2心目中男生A的优先级比男生B高这种情况。

算法的流程及其稳定性

算法流程

  1. 第一轮,每个男生选择最喜欢的女生,并且向女生表白。这个时候女生有三种情况:①没有追求者,继续保持单身的状态。②有一个追求者,答应结束单身状态。③有多个追求者,选择最喜欢的男生并且拒绝其他的男生。

  2. 第二轮,剩下的单身男生划去刚才追求失败的女生的序号,从剩余的序号中选择最喜欢的女生。这个时候若女生第一轮后保持单身,像之前的三种方式处理。若在第一轮女生结束了单身的状态,此时会遇到两种情况:①这一轮没有男生追求,保持该状态。②有男生追求,这个时候选择最喜欢的男生(包括之前答应的男生)。若在此时有更喜欢的男生,抛弃之前答应的男生,第一轮的男生变成单身状态,更喜欢的男生结束单身状态,并且拒绝其他的所有的男生。或者第一轮的男生在追求者依旧是最喜欢的,保持该关系,拒绝其他男生。

  3. 按照上面的规则不断的进行男生求婚,女生选择最优的男生并且拒绝其他男生的步骤来完成筛选的过程。

算法的正确性说明

我们讨论是否会出现一对男女,他们彼此间的爱慕程度都比现任的男女朋友高,但是现在并没有在一起。
我们直接给出一个例子:
男生A(1, 2) 女生(A, B)
男生B(1, 2) 女生(B, A)

那么婚姻匹配的结果只能是A-1, B-2.会不会出现A-2, B-1的情况能?
答案是否定的。

  • 假设一开始B和1是男女朋友,当男生A向女生1发出请求的时候,那么女生1会改变男朋友而选择B。
  • 假设一开始A和1是男女朋友,当男生B向女生A发出请求的时候,那么女生1会保持原来的状态拒绝B。
    综上,不会发生不稳定的情况。

算法的稳定性

那么算法会不会陷入一个死循环呢?答案是不会的。
简单说明:
一旦女生处于脱单的状态,那么该女生将会一直处于脱单的状态
假设有n个男生,n个女生,那么意向的表的规模是\(n^2\)的,算法一定能将表依次的处理完(具体的处理过程看最开始推荐的博客),由于意向表使得一定所有的女生会被表白。(哪怕所有的男生的爱慕表的最后一位都是同一个女生,这个女生也是可以脱单的)

1175 - Ladies’ Choice

1175 - Ladies’ Choice

题意

题解

很裸的一道稳定婚姻匹配问题,按照上面的步骤来操作就行了。
时间复杂度O(\(n^2\))
注意第一个输入的是女生的喜欢男生的列表。
第二个是男生的喜欢女生的列表。
要求输出的是第i个女生匹配的男生的序号和下面的男女性别是不同的含义,但是结果是一样的。

题目是女生来选男生,下面的代码使男生来选择女生

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
//pref是男生的爱慕程度表,order是女生的爱慕表,nex数组是男生选择女生的顺序
int pref[maxn][maxn], order[maxn][maxn], nex[maxn];
int future_husband[maxn];
int future_wife[maxn];
queue<int> q;
int n;
void engage(int man, int woman){
int m = future_husband[woman];
//m不为0说明女生之前有男朋友,那么抛弃前男友,和新的男生匹配。
if(m!=0){
future_wife[m] = 0;
q.push(m);//背弃的男生加入匹配的队列
}
future_husband[woman] = man;
future_wife[man] = woman;
}
int main()
{
int kase=0;
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
while(!q.empty()) q.pop();
if(++kase>1)printf("\n");
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
scanf("%d", &pref[i][j]);//编号为i的男生第j喜欢的女生
}
future_wife[i] = 0; //未脱团初始化为0
nex[i] = 1; //向排名第一名女生表白
q.push(i); //进入脱单的匹配队列
}
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
int temp;
scanf("%d", &temp);
order[i][temp] = j; //编号为i的女生男生temp在女生心中的序号
}
future_husband[i] = 0;
}
while(!q.empty()){
int man = q.front();
q.pop();
int woman = pref[man][nex[man]];
nex[man]++;
if(!future_husband[woman]) engage(man, woman);//若女生处于单身状态,直接匹配
//现在匹配的男生比之前的男朋友更优,女生舍弃前男友而选择现在的男生
else if(order[woman][man]<order[woman][future_husband[woman]]){
engage(man, woman);
}
//未被选中,男生进入下一轮的匹配
else q.push(man);
}
for(int i=1; i<=n; i++){
printf("%d\n", future_wife[i]);
}
}
return 0;
}

说明:该算法每次选择一个单身的男性进行匹配,根据情况男生被匹配或者被拒绝再次进行匹配。
又每一个男生最多考虑每个女生依次,时间复杂度为O(\(n^2\))。并且进一步的说明了该算法的稳定性,一定不会陷入死循环。

有趣的现象

我们从上面的思想中看到了一个很有意思的现象:男生处于相对的主动的地方,不断的选择自己最喜欢的女生,虽然可能会被拒绝。
女生处于一个相对被动的位置,不断的接受最喜欢男生的请求。
结论:男生所得到的结果是不断的变坏的,女生选择结果是不断的变好的这两种趋向最后变成了最稳定的匹配,感觉很有意思。

未解决的问题

文章目录
  1. 1. 算法问题及介绍
  2. 2. 需要解决的问题
  3. 3. 算法的流程及其稳定性
    1. 3.1. 算法流程
    2. 3.2. 算法的正确性说明
    3. 3.3. 算法的稳定性
  4. 4. 1175 - Ladies’ Choice
  5. 5. 题意
  6. 6. 题解
  7. 7. AC代码
  8. 8. 有趣的现象
  9. 9. 未解决的问题
{{ live2d() }}