HDU-1914-The Stable Marriage Problem(稳定婚姻算法)

The Stable Marriage Problem

Problem Description

The stable marriage problem consists of matching members of two different sets according to the member’s preferences for the other set’s members. The input for our problem consists of:

a set M of n males;
a set F of n females;

for each male and female we have a list of all the members of the opposite gender in order of preference (from the most preferable to the least).
A marriage is a one-to-one mapping between males and females. A marriage is called stable, if there is no pair (m, f) such that f ∈ F prefers m ∈ M to her current partner and m prefers f over his current partner. The stable marriage A is called male-optimal if there is no other stable marriage B, where any male matches a female he prefers more than the one assigned in A.

Given preferable lists of males and females, you must find the male-optimal stable marriage.

Input

The first line gives you the number of tests. The first line of each test case contains integer n (0 < n < 27). Next line describes n male and n female names. Male name is a lowercase letter, female name is an upper-case letter. Then go n lines, that describe preferable lists for males. Next n lines describe preferable lists for females.

Output

For each test case find and print the pairs of the stable marriage, which is male-optimal. The pairs in each test case must be printed in lexicographical order of their male names as shown in sample output. Output an empty line between test cases.

Sample Input

2
3
a b c A B C
a:BAC
b:BAC
c:ACB
A:acb
B:bac
C:cab
3
a b c A B C
a:ABC
b:ABC
c:BCA
A:bac
B:acb
C:abc
 

Sample Output

a A
b B
c C

a B
b A
c C

解题思路:

参考:https://blog.csdn.net/u013761036/article/details/39852667

稳定婚姻问题就是给你n个男的,n个女的,然后给你每个男生中女生的排名,和女生心目中男生的排名,然后让你匹配成n对,使婚姻稳定,假如a和b匹配,c和d匹配,如果a认为d比b好,同时d也认为a比c好,那么ad就有可能私奔,这样就导致了婚姻的不稳定,稳定婚姻就是找到一种解决方案让婚姻稳定
算法:
稳定婚姻的解决方法比较简单,通俗易懂,而且还容易实现,具体有没有固定的模板我不知道,没有去找,自己模拟的,在求解的过程中,我们先把所有的男生都加到队列里,队列里的就表示当前还单身的男生,每次从队列里拿出一个男生,然后从她最喜欢的女生开始匹配,如果当前的女生尝试追求过,那么就不用追求了,如果当前的女生没有伴侣,那么可以直接匹配上,如果有伴侣,那么就看看当前这个男生和女生之前的伴侣在那个女生中更喜欢谁,如果更喜欢当先的这个男生,那么当前男生就和这个女生匹配,女生之前匹配过的直接变成单身,被扔回队列,否则,继续找下一个女生,知道找到一个能匹配上的为止,就这样一直到队列空的时候,就已经全部匹配完成了。

正确性:

    对于男生来说,每次都是从最喜欢的女生开始匹配的,遇到的第一个没人能抢走的并且稳定的就是自己最终伴侣,也就是说如果之前追求过的女生被别人抢走了,那么他将永远抢不会来,因为对于女生来说,第一次被男士按照自己的意愿选择之后,每次变更匹配对象都是在自己心目中更加喜欢的,所以一旦他放弃了某个男生,那么那个男生就没希望在和他匹配,这样男生是从最优的选的,保证男生不会出轨,女生每次都是在选择她的男生中选择最优的,这样也保证了女生最后没有怨言,这样的话,最后的到的婚姻就是稳定的,至于稳定婚姻,肯定会有稳定方案,这个我暂时证明不了.<1962年,美国数学家 David Gale 和 Lloyd Shapley是这两个人发明的方法,并且证明了稳定婚姻一定会有解>。

————————————————
版权声明:本文为CSDN博主「TK13」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013761036/article/details/39852667

AC代码:

//#include <iostream>
//#include <cmath>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod =  1e9 + 7;
const int N = 1e6+10;
struct node{
    char name;
    char prefer[50];
    char par;
    int num;
    int pos;
}men[50],women[50];
int vis[50],vis2[50];
queue<node> que;


int main()
{
    int t;
    scanf("%d",&t);
    getchar();
    while(t -- )
    {
        int n;
        scanf("%d",&n);
        getchar();
        memset(vis,0,sizeof(vis));
        memset(vis2,0,sizeof(vis2));
        for(int i= 0 ; i < n ; i ++)
        {
            char tmp;
            tmp = getchar();
            getchar();
            men[tmp-'a'].name = tmp;
            men[tmp-'a'].num = 0;
            men[tmp-'a'].pos = 0;
            men[tmp-'a'].par = 0;
            vis[tmp-'a'] = 1;

        }
        for(int i = 0 ; i < n  ; i ++)
        {
            char tmp;
            tmp = getchar();
            getchar();
            women[tmp-'A'].name = tmp;
            women[tmp-'A'].num = 0;
            women[tmp-'A'].par = 0;
            women[tmp-'A'].pos = 0;
        }
        for(int i = 0 ; i < n ; i ++)
        {
            char tmp;
            char name;
            name = getchar();
            tmp = getchar();
            tmp = getchar();
            int pos = 0;
            while(tmp != '\n')
            {
                men[name-'a'].prefer[men[name-'a'].num++] = tmp;
                tmp = getchar();
            }
        }
        for(int i = 0 ; i < n ; i ++)
        {
            char tmp;
            char name;
            name = getchar();
            tmp = getchar();
            tmp = getchar();
            int pos = 0;
            while(tmp != '\n')
            {
                women[name-'A'].prefer[women[name - 'A'].num++] = tmp;
                tmp = getchar();
            }
        }
        while(!que.empty())
            que.pop();
        for(int i = 0 ; i < 30 ; i ++)
        {
            if(vis[i])
            {
                que.push(men[i]);
            }
        }
        while(!que.empty())
        {
            node tmp1 = que.front();
            que.pop();
            for(int i = 0 ; i < tmp1.num ; i ++)
            {
                if(!vis2[tmp1.prefer[i]-'A'])
                {
                    tmp1.par = tmp1.prefer[i];
                    men[tmp1.name-'a'].par = tmp1.prefer[i];
                    vis2[tmp1.prefer[i]-'A'] = 1;
                    women[tmp1.prefer[i]-'A'].par = tmp1.name;
                    break;
                }
                else
                {
                    node tmp2 = women[tmp1.prefer[i]-'A'];
                    int pos1 = 0,pos2 = 0;
                    for(int i = 0 ; i < tmp2.num ; i ++)
                    {
                        if(tmp2.prefer[i] == tmp1.name)
                            pos1 = i;
                        if(tmp2.prefer[i] == tmp2.par)
                            pos2 = i;
                    }
                    if(pos1 < pos2)
                    {
                        tmp1.par = tmp1.prefer[i];
                        men[tmp1.name-'a'].par = tmp1.prefer[i];
                        men[women[tmp1.prefer[i]-'A'].par - 'a'].par = 0;
                        que.push(men[women[tmp1.prefer[i]-'A'].par - 'a']);
                        women[tmp1.prefer[i]-'A'].par = tmp1.name;
                        break;
                    }
                }
            }
        }
        for(int i = 0 ; i < 30 ; i ++)
        {
            if(vis[i])
                cout<<men[i].name<<" "<<men[i].par<<endl;
        }
        if(t)
            cout<<endl;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值