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

【稳定婚姻问题】

1.集合 M 表示 n 个男性

2.集合 F 表示 n 个女性

3.对于每个人我们都按异性的中意程度给出一份名单(从最中意的到最不中意的)

如果没有 (m,f),f\in F,m\in M,f 对 m 比对她的配偶中意的同时 m 对 f 比对他的配偶更加中意,那么这个婚姻是稳定的。

如果一个稳定配对不存在另一个稳定婚姻配对,那么这样的配对方案是稳定的。

用 A、B 给男性标号,用 1、2 给女性标号,将所有男性从上到下列在左侧,括号里的数字表示对所有女性的排名,再把所有女性列在右侧,用括号里的字母表示她们对所有男性的排名。

如下图,每个男的都喜欢女 1,但女 1 更喜欢男 B,女2 更喜欢男 A,若按 A-1,B-2 进行搭配,则男 B 和女 1都更喜欢对方,这样的婚姻搭配就是不稳定的。

但若按 A-2,B-1 的方案进行搭配,这样的搭配就是稳定的了

【修补策略】

可能很多人会立即想到一种寻找稳定婚姻搭配的策略:不断修补当前搭配方案,如果两个人互相都觉得对方比自己当前的伴侣更好,就让这两个人成为一对,剩下被甩的那两个人一对。如果还有想要私奔的男女对,就继续按照他们的愿望互换情侣,直到最终消除所有的不稳定组合。

容易看出,应用这种 “修补策略” 所得到的最终结果一定满足稳定性,但这种策略的问题在于,它不一定存在 “最终结果”,应用这种策略反复调整方案,最终可能会陷入一个死循环,因为该策略不能保证得出一个确定的方案来。

【延迟认可算法】

1.概述

延迟认可算法是由 David Gale 和 Lloyd Shapley 发明的一种寻找稳定婚姻的策略,因此也叫 Gale-Shapley 算法。

该算法的最大意义在于,并不需要亲自了解每个人的偏好,去计算稳定婚姻匹配,只需按照这个算法组织一个活动,将算法流程当作游戏规则告诉每个人,当活动结束后,会自动得到一个大家都满意的婚姻匹配。

2.算法流程

在这种策略中,男性将一轮一轮的去追求他中意的女性,女性可以选择接受或者拒绝她的追求者。

1)第一轮

每个男性都去选择自己名单上排名首位的女性,向她表白。

此时,一个女性可能面对的有三种情况:① 没有人向她表白;② 只有一个人向她表白 ③ 不止有一个人向她表白

在情况 ① 下,这个女性事情都不用做,只需等待下一轮

在情况 ② 下,接受那个人表白,并暂时与他在一起

在情况 ③ 下,选择所有追求者最中意的一位,并暂时和他在一起

第一轮结束后,有些男性已经有女朋友了,但有些男性仍然是单身。

2)第二轮

每个单身男性都从所有还没拒绝过自己的女性中选择自己最中意的那个,不管她是否单身。

与第一轮一样,女性们需要选出自己最中意的那个,并暂时和他在一起。如果这个女性已经有男朋友了,当她遇到了更好的追求者时,她必须拒绝掉现在的男友,投向新的追求者的怀抱。

这样,一些单身男性将会得到女友,那些已经有了女友的人可能重新单身。

3)以后的每一轮

以第一、二轮为例,在以后的每一轮,单身男性继续追求其列表中的下一个女性,女性则从包括现男友在内的所有追求者中选择最好的一个。

这样一轮一轮的继续下去,直到某个时候所有人都不再单身,下一轮将不会再有新的表白发生,整个过程自动结束,此时的婚姻搭配一定是稳定的。

3.稳定性证明

随着轮数的增加,总有一个时候所有人都能配对,不会像之前的 “修补策略” 一样出现无法终止的情况。

由于在每一轮中,至少有一个男性向某个女性告白,因此总的告白次数将随着轮数的增加而增加,倘若这个流程一直没有因所有人都配上对了而终止,最终必然会出现某个男性追遍了所有女性的情况,而一个女性只要被人追过一次,以后就不可能单身了。既然所有女性都被这个男性追过,那么就说明所有女性现在都不是单身,也就是说此时所有人都已配对。

随着轮数的增加,一个男性追求女性的对象总是越来越糟,但一个女性的男友只可能变得越来越好。假设男 A 和女 1 各有各自的对象,但比起现在的对象,男 A 更喜欢女 1,因此男 A 之前肯定向女 1 表白过,既然女 1 最后没有跟男 A 在一起,那么说明女 1 拒绝了男 A,也即说明女 1 有了比男 A 更好的男性。

这就证明了,两个 人虽然不是一对,但都觉得对方比自己现在的伴侣好的情况绝不会发生。 

4.算法简述与有利性分析

整个算法可以简述为:每个人都去做自己想做的事情,对于男性来说,从最喜欢的女性开始追是顺理成章的,对于女性来说,不断选择最好的男性符合她的利益,因此所有人会自动遵循规则,不用担心有人虚报偏好。

事实上,稳定婚姻搭配往往不止一种,然而上述算法的结果可以保证,每一位男性得到的伴侣都是所有可能的稳定婚姻搭配方案中最理想的,同时每一位女性得到的伴侣都是所有可能的稳定婚姻搭配方案中最差的。

【实现】

int couple;//总共多少对
int Male_Like[N][N];//男性对女性的喜欢程度
int Female_Like[N][N];//女性对男性的喜欢程度
int Male_Choice[N];//男性的选择
int Female_Choice[N];//女性的选择
int Male_Name[N],Female_Name[N];//姓名的hash
queue<int> Free_Male;//没有配对的男性
char str[N];
int main(){
    scanf("%d",&couple);
 
    while(!Free_Male.empty())//清空队列
        Free_Male.pop();
 
    for(int i=0;i<couple;i++){//存入男性名字,初始都没有配对
        scanf("%s",str);
        Male_Name[i]=str[0]-'a';
        Free_Male.push(Male_Name[i]);
    }
 
    for(int i=0;i<couple;i++){//存入女性名字,初始都没有配对
        scanf("%s",str);
        Female_Name[i]=str[0]-'A';
    }
 
    sort(Male_Name,Male_Name+couple);//对名字排序
 
    for(int i=0;i<couple;i++){//男性对女性的印象,按降序排列
        scanf("%s",str);
        for(int j=0;j<couple;j++)
            Male_Like[i][j]=str[j+2]-'A';
    }
 
    for(int i=0;i<couple;i++){//女性对男性的印象,添加一虚拟人物,编号为couple,为女性初始对象
        scanf("%s",str);
        for(int j=0;j<couple;j++)
            Female_Like[i][str[j+2]-'a']=couple-j;
        Female_Like[i][couple]=0;
    }
 
    memset(Male_Choice,0,sizeof(Male_Choice));//所有男性初始选择都是最喜欢的女性
 
    for(int i=0;i<couple;i++)//先添加女性的初始对象
        Female_Choice[i]=couple;
 
    while(!Free_Male.empty()){
        int male=Free_Male.front();//找出一个未配对的男性
        int female=Male_Like[male][Male_Choice[male]];//男性心仪的女性
 
        //女性对男性的喜爱度大于当前对象
        if(Female_Like[female][male]>Female_Like[female][Female_Choice[female]]){
            Free_Male.pop();//男性脱单
 
            if(Female_Choice[female]!=couple){//如果有前男友且不为虚拟对象couple
                Free_Male.push(Female_Choice[female]);//其前男友进入队列,重新变为光棍
                Male_Choice[Female_Choice[female]]++;//其前男友考虑其下一对象
            }
 
            Female_Choice[female]=male;//当前男友为当前男性
        }
        else//如果被女性拒绝
            Male_Choice[male]++;//考虑下一对象
    }
 
    for(int i=0;i<couple;i++){
        printf("%c ",Male_Name[i]+'a');
        ptintf("%c\n",Male_Like[Male_Name[i]][Male_Choice[Male_Name[i]]]+'A');
    }
 
    return 0;
}

【例题】

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值