Poj 3487 稳定婚姻问题

10 篇文章 0 订阅
1 篇文章 0 订阅

稳定婚姻问题:有n个男人,n个女人。每个人都有一个对异性的排名(1~n),假设男人主动追求女人,根据这些排名,我们需要将这些男女进行牵线,使得他们的婚姻稳定。

    由于稳定不太好定义,我们定义一下不稳定。

不稳定婚姻:对于任意一个男人m, 假设其当前配偶为w, 若存在一个女人w1, 其当前配偶为 m1, 她在m 的排名中比 w 靠前,同时,m在 w1 的排名中比她现任丈夫 m1靠前,这时候我们称婚姻(m, w)为不稳定婚姻。

整个男女集合中不存在不稳定婚姻则这个集合为稳定婚姻集合。

那么,如何找到稳定婚姻呢? 算法步骤:

从第一个男人开始,找到其排名中最高的女人,

若这个女人单身,则

两人结合

否则若当前男人在这个女人的排名比其现任丈夫高,则

则当前男人与这个女人结合。这个女人原丈夫变为单身。

直到所有男人都找到配偶算法结束。


POJ 3487是一道稳定婚姻的入门题。因为需要处理的是字符串,所有这道题的存储结构稍微有点麻烦,用了两次哈希。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>

using namespace std;

const int N = 32;

typedef vector<char>::iterator vc_i;

char male[N];
char female[N];
char in[128];
int hs[256];
int nhs[256];
int matched[256];
queue<int> que;


vector<char> G[N<<1];

int getLev(int f, char m)
{
    int ret = 0;
    for(vc_i i = G[f].begin(); i != G[f].end(); i++)
    {
        if(*i == m) break;
        ret ++;
    }
    return ret;
}

int main()
{
    int t;
//    freopen("in.txt", "r", stdin);
    scanf("%d", &t);
    getchar();
    while(t--)
    {
        int n;
        scanf("%d", &n);
        memset(hs, -1, sizeof(hs));
        memset(matched, -1, sizeof(matched));
        getchar();
        for(int i = 0; i < n; i++){
            scanf("%c", &male[i]);
            getchar();
        }

        for(int i = 0; i < n; i++){
            scanf("%c", &female[i]);
            getchar();
        }

        int num = 0;
        for(int i = 0; i < n; i++){
            gets(in);
            int j = 2;
            int len = strlen(in);
             if(hs[in[0]] == -1) {
                G[num].clear();
                hs[in[0]] = num;
                nhs[num++] = in[0];
            }
            for(; j < len; j++)
                G[hs[in[0]]].push_back(in[j]);
            que.push(i);
        }
        for(int i = 0; i < n; i++){
            gets(in);
            int j = 2;
            int len = strlen(in);
            if(hs[in[0]] == -1) {
                    G[num].clear();
                hs[in[0]] = num;
                nhs[num++] = in[0];
            }
            for(; j < len; j++)
                G[hs[in[0]]].push_back(in[j]);
        }
        while(!que.empty()){
            int i = que.front();
            que.pop();
                for(vc_i j = G[i].begin(); j != G[i].end(); j++)
                {
                    if(matched[hs[*j]] == -1)
                    {
                        matched[i] = hs[*j];
                        matched[hs[*j]] = i;
                        break;
                    }
                    else{
                        if(getLev(hs[*j], nhs[i]) < getLev(hs[*j], nhs[matched[hs[*j]]])){
                            que.push(matched[hs[*j]]);
                            matched[matched[hs[*j]]] = -1;
                            matched[i] = hs[*j];
                            matched[hs[*j]] = i;
                            break;
                        }
                    }
                }
        }
//        sort(nhs, nhs + n);  //根据题意是需要排序的,但没排序也过了。
        for(int i = 0; i < n; i++)
            printf("%c %c\n", nhs[i], nhs[matched[i]]);
        puts("");
    }
    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值