UVALive 3989 Ladies' Choice(稳定婚姻问题、Gale-Shapley算法)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1990
题目大意:一个很大的舞会,有n个男士和n个女士,每个人都对所有的异性的喜欢程度有一个排名,现在要配对。配对好了之后,不存在说有人没有舞伴,或者,有两个人,他们彼此喜欢的程度都大于各自的当前舞伴,这样的话,他们两个会跑出来组成一对。现在让你找出每个女生在最好情况下的男舞伴编号。
解题思路:这是稳定婚姻问题,不稳定了,都比现任更喜欢对方,就一起跑了呗,结婚和舞伴,类比一下即可。解决这个问题,用Gale-Shapley算法,也称为求婚-拒绝算法,因为这个算法中男士不断地求婚,女士不断地拒绝。

        算法的过程:每一轮,每个尚未订婚的男士根据自己的喜欢程度,在没有被拒绝过的里面,选择一个自己最喜欢的女士求婚,如果女士没有订婚或者那个女士对她的的现任的喜欢程度不如当前这个求婚的,那么他就会答应,然后和他订婚,否则就是他被拒绝了,在继续求婚去。就这样一直搞就行了。搞到最后,结果一定是满足条件的。最后假设有A和B,C和D,有没有可能出现A、D相互喜欢的程度低于B和C?不可能,因为如果是这样,那么A肯定之前就想D求过婚,而D拒绝了他,这样就说明D的现任比A好,而C肯定是>=她那时的现任的。然后还有很重要的一点:这个算法看似对男士来说很残酷,一直求婚被拒,其实最后结果是男士都能找到自己能娶到的最好的妻子,而女士则相反,只能嫁给自己有可能嫁到的最差的丈夫。因为男士是主动的,根据自己的喜欢程度依次求婚,被拒的就是不可能的,而女士是被动的,自己喜欢的可能没有向她求婚而已经订婚了。这一点貌似和现实有点像,还是死皮赖脸一点比较好。。。= =

        这一题,由于是在女生最好情况下,那么就是女生去求婚。

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int MAXN = 1111;

struct GS
{
    int n;
    int mr[MAXN][MAXN],miss[MAXN][MAXN];
    int future_wife[MAXN],future_husband[MAXN],next[MAXN];
    queue<int> q;

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

    void read()
    {
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j <= n;j++)
                scanf("%d",&mr[i][j]);//编号为i的男士第j喜欢的女士
            next[i] = 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);
                miss[i][x] = j;//在编号为i的女士心中编号为x的男士排名
            }
            future_husband[i] = 0;//没有未婚夫
        }
    }

    void solve()
    {
        while(!q.empty())
        {
            int man = q.front();
            q.pop();
            int woman = mr[man][next[man]++];//下一个求婚对象
            if(!future_husband[woman])//如果没有未婚夫
                engage(man,woman);//订婚
            else if(miss[woman][man] < miss[woman][future_husband[woman]])//如果他求婚的对象比起她的现任跟喜欢他
                engage(man,woman);//订婚
            else q.push(man);//被拒绝,加入未订婚男士队列,继续求婚
        }
    }

    void init(int n)
    {
        this->n = n;
    }
} gs;

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n;
        scanf("%d",&n);
        gs.init(n);
        gs.read();
        gs.solve();
        for(int i = 1;i <= n;i++)
            printf("%d\n",gs.future_wife[i]);
        if(_) puts("");
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值