定义
题意:有 男 女,每一个人都对其他 个异性有不同程度的喜爱,用一个长为 的列表表示,列表中的异性按喜爱程度从高到低排列。问能否找出一个结婚方案,使得不存在两对夫妻 ,使得 比起 更喜爱 , 比起 更喜爱 ,
如果两对夫妻 没有上述情况就称这两对夫妻是稳定的,否则就是不稳定的。
用图论的语言描述,我们要找的结婚方案就是二分图中的一个完美匹配,且要是一个稳定匹配。
Gale-Shapley 算法
这是一个符合直觉的算法,直接写成伪代码就能表述意思。
初始化:所有男女都没有对象
WHILE 还有某个男性没有对象,且其尚未追求过所有女性
选择这样一个男性 m
设 w 为 m 尚未追求过的,且 m 喜爱程度最高的女性
IF w 没有对象
让 (m, w) 暂时结对
ELSE
设当前 w 与 m' 是一对
IF w 比起 m' 更喜欢 m
让 (m, w) 暂时结对,m' 变为没有对象
ELSE
m 被拒绝,仍然没有对象
END
最后所有结对的男女即成夫妻。
算法正确性
-
算法是否会终止?
会,在 轮内终止。原因显然。
-
算法是否找到完美匹配?
是,否则必然有一对男女都没有对象,而该男性由于没有对象一定会追求该女性,使得两者结对。
-
算法是否找到稳定匹配?
是,考虑最终结果中任意两对夫妻 。如果 追求过 ,那么 比起 更喜爱 ;否则由于男性按照喜爱程度降序选择女性, 比起 更喜爱 。无论哪种情况,这两对夫妻都是稳定的。
算法其他特性
定义女性 是男性 的可行对象(valid partner),若存在某个稳定匹配,使得 是一对夫妻。对女性的男性可行对象定义类似。
定理:无论以何种方式实现算法,算法都只会返回唯一的结果。且该结果满足:
- 对任意男性最优:算法给出的其妻子,都是所有可行对象中,他的喜爱程度最高的。
- 对任意女性最劣:算法给出的其丈夫,都是所有可行对象中,她的喜爱程度最低的。
证明:设算法给出的匹配是 。我们先证明第一点。
考虑反证。由于男性追求女性是按照喜爱程度降序,因此如果存在男性 ,使得其妻子 不是所有可行对象中, 的喜爱程度最高的,那么 已经被之前的某个喜爱程度更高的可行对象 拒绝过了。
不妨假设 是算法执行过程中第一个受到如此待遇的男性。按照定义,存在另一个稳定匹配 ,使得 是一对夫妻。
设 中, 的丈夫是 。显然 喜爱 甚于 。
再设 中, 的妻子为 。那么由于之前所设, 是第一个被更喜爱的可行对象拒绝的男性,那么 会在 中与 而不是 结婚,就只能是因为 喜爱 甚于 。否则, 会先追求 ,被拒绝后才会追求 ,而这与之前所设矛盾。
由此可得在 中, 是不稳定的两对夫妻,这与 是稳定匹配相矛盾。
再证明第二点。假设算法给出的匹配 中存在女性 ,使得其丈夫 不是所有可行对象中, 的喜爱程度最低的,那么存在另一个稳定匹配 ,使得 与所有可行对象中喜爱程度最低的 结对。显然, 喜爱 甚于 。
设 在 中的妻子是 。那么由于男性最优性, 喜爱 甚于 。这导致 是不稳定的两对夫妻,这与 是稳定匹配相矛盾。
代码实现
以 UVa 1175 为例,实现这一算法。时间复杂度为 。
int n, pref[1005][1005], rnk[1005][1005];
// 分别为男对女的喜爱值列表,女对男的喜爱值排名(降序)
int cur[1005], wife[1005], husband[1005];
// 当前追求到哪一个
queue<int> q;
// 用队列辅助求解
void GS(){
memset(wife, 0, sizeof(wife));
memset(husband, 0, sizeof(husband));
for (int i = 1; i <= n; ++i)
cur[i] = 1, q.push(i);
while (!q.empty()){
int h = q.front();
q.pop();
int targ = pref[h][cur[h]++];
if (!husband[targ] || rnk[targ][h] < rnk[targ][husband[targ]]){
wife[h] = targ;
if (husband[targ] > 0){
wife[husband[targ]] = 0;
q.push(husband[targ]);
}
husband[targ] = h;
} else if (cur[h] <= n){
q.push(h);
}
}
for (int i = 1; i <= n; ++i)
printf("%d\n", wife[i]);
}
参考资料
- 《Algorithm Design》