LA 3989 Ladies'Choice(稳定婚姻问题)

问题:n个男生与n个女生进行配对,每个人恰好一个舞伴。若不存在:男u和女v没有配对,而他们喜欢对方的程度大于各自当前的舞伴程度。


Gale-Shapley算法步骤:

1、每个尚未匹配的男生在他还没有邀请的女生中选一个自己最喜欢的。

2、若被邀请的女生没有舞伴,则接受邀请;若已经有了舞伴,比较当前舞伴与该男生排名,若当前舞伴排名较低,则抛弃之,接受当前邀请,反之拒绝邀请。

3、若该轮男生没有找到舞伴,则再次加入到未匹配队伍中。


算法正确性证明:

  对以上算法进行分析,我们会发现两个现象:1、女人从接到第一个求婚起就开始一直保持约会的状态,并且她约会的对象会越来越好(从她的排序表来看);2、男人求婚的对象(女人)会越来越差!

下面,我们对这个算法的正确性证明如下:
1、算法的有限性——算法最多会在执行完n2次while循环的时候结束:每次while循环,一个男人向一个女人求婚,因为一共有n个男人和n个女人,所以最多只有n2次求婚。
2、算法的完美性——所有的男女都进行了配对:(反证法)假设男人M在算法结束后没有配对,那么相应的肯定会存在一个女人假设为W也没有配对,那么可以肯 定女人W从来都没有收到求婚的请求,但是根据现象2,男人M会向所有的女人求婚一直到有人接受,那么矛盾就出现了,于是假设不成立,命题得证。
3、算法的稳定性——不存在不稳定对:(反证法)假设在GS配对里,Amy-Yancey、Bertha-Zeus分别是2对,假设A—Z是不稳定对,那 么出现这种现象有两种可能:a、Z从来没有向A求婚,根据现象2,得出Z会更喜欢他的GS对象,而不是A,那么A—Z就是稳定的;b、Z向A求过婚,但是 被A拒绝了(可能是当场拒绝,也可能是后来A遇到更好的抛弃了Z),那么也可以得出A更喜欢她的GS对象,而不是Z,所以A—Z也是稳定的。所以在任何情 况下,A—Z都是稳定的,假设不成立,命题得证。


#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
#define N 1005
int pref[N][N],order[N][N],next[N];
int future_husband[N],future_wife[N];
queue<int>q;

//订婚
void engage(int man,int woman){
    int m=future_husband[woman];
    if(m){          //女士有现任未婚夫m
        future_wife[m]=0;//抛弃m
        q.push(m);  //m加入未婚男士队列
    }
    future_wife[man]=woman;
    future_husband[woman]=man;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j)
                scanf("%d",&pref[i][j]);
            next[i]=1;      //接下来应该向排名为1的女士求婚
            future_wife[i]=0;//无未婚妻
            q.push(i);      //未婚男士队列
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                int x;
                scanf("%d",&x);
                order[i][x]=j;  //在编号为i的女士心目中,编号为x的男士的排名
            }
            future_husband[i]=0;    //无未婚夫
        }
        while(!q.empty()){
            int man=q.front();q.pop();
            int woman=pref[man][next[man]++];   //指向当前求婚对象,并使next后移一个
            if(!future_husband[woman])//女士没有未婚夫
                engage(man,woman);
            else if(order[woman][man]<order[woman][future_husband[woman]])//代替女士的现任未婚夫
                engage(man,woman);  //排名比现任未婚夫靠前,代替女士的现任未婚夫
            else q.push(man);   //被拒
        }
        while(!q.empty()) q.pop();
        for(int i=1;i<=n;++i) printf("%d\n",future_wife[i]);
        if(t) puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值