Marriage is Stable

这里写图片描述

这里写图片描述

//题意:(稳定婚姻问题)尽量找男对女,女对男好感度都比较高的配对
举个反例:现在男A和女a是情侣,如果男B也喜欢女a,而女a也更喜欢男B,那么男B和女a就很可能好上了,给男A戴绿帽子,所以这种婚姻是不稳定的。

//思路:Gale-Shapley算法

算法介绍:

1.先给男生心目中对女生的好感度排个序,同理,也给女生心目中对男生的好感度排。

2.男生去追女生(男的当然应该主动点),每个男生按好感顺序(好->差)去追女生。

1)若女生现在还没男朋友,两人就先配对,去约会了。

2)若女生有男朋友了,但对这个男生的好感度比对她男朋友的好感度还要高,那么就果断甩了男朋友,跟现在这个男生在一起。(心疼被戴绿帽子的男生一秒)之前那个男生回归单身。

3)循环重复1)2)直到所有男女都配对成功
注:如果男生之前被这个女生甩过,就不用再去追她了,因为那个女生对她男朋友的好感度肯定比他高(就是因为这样才被甩的…)

还有,稳定婚姻问题必然有解,美国数学家David Gale和Lloyd Shapley已经证明过了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <algorithm>
using namespace std;

#define MAX 500+10

typedef struct {
    char name[30];  //名字
    char Love[MAX][30];  //按对异性的好感程度存放的异性名字
    bool is_date; //是否已经和异性在约会
}Person;

int n;
Person B[MAX], G[MAX]; //B:boy  G:girl

 //男的心目中对女的好感程度的排名
 //前[]:男孩的编号  后[]:好感度  
 //B_G[][]:女孩的编号
int B_G[MAX][MAX];

//女的心目中对男的好感程度的排名
//前[]:女孩的编号  后[]:男孩的编号
//G_B[][]:好感度
int G_B[MAX][MAX]; 

int man[MAX]; //男孩的匹配对象
int women[MAX]; //女孩的匹配对象

//寻找名字是str的女孩的编号
int findboy(char str[])
{
    for (int i = 1; i <= n; i++)
    {
        if (strcmp(str, G[i].name) == 0)
            return i;
    }
}

//寻找名字是str的男孩的编号
int findgirl(char str[])
{
    for (int i = 1; i <= n; i++)
    {
        if (strcmp(str, B[i].name) == 0)
            return i;
    }
}

//给B_G[][]赋值
//女孩在男孩心目中的排名
void BoyRank()
{
    int i, j;
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            B_G[i][j] = findboy(B[i].Love[j]);
        }
    }
}

//给G_B[][]赋值
//男孩在女孩心目中的排名
void GirlRank()
{
    int i, j;
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            G_B[i][findgirl(G[i].Love[j])] = j;
        }
    }
}

//Gale-Shapley算法
//介绍见思路
//循环实现是便于理解,这样很容易TLE,一般用队列实现
//如果男孩追过一个女孩,后来被甩了,再去匹配的时候就不用再追这个女孩了
//但这个剪枝这里没用,这题很水,怎么都能过QAQ
void GS()
{
    int i, j, ok = 1;
    memset(man, 0, sizeof(man));
    memset(women, 0, sizeof(women));

    //要进行到所有男孩都找到女朋友为止
    while (ok == 1)
    {
        ok = 0;
        for (i = 1; i <= n; i++)
        {
            if (man[i] == 0)
            {
                ok = 1;
                for (j = 1; j <= n; j++)
                {
                    //该女孩现在的男朋友的编号
                    int womenpos = women[B_G[i][j]]; 

                    //若这个女孩还没有男朋友,两人就直接配对
                    if (G[B_G[i][j]].is_date == false)
                    {
                        man[i] = B_G[i][j];
                        women[B_G[i][j]] = i;
                        G[B_G[i][j]].is_date = true;
                        break;
                    }

                    //若女孩对这个男孩更有好感,就甩了之前那个男的
                    //和现在这个男的配对,之前那个男的回归单身
                    else if (G_B[B_G[i][j]][i] < G_B[B_G[i][j]][womenpos])
                    {
                        man[womenpos] = 0;
                        man[i] = B_G[i][j];
                        women[B_G[i][j]] = i;
                        break;
                    }
                }
            }
        }
    }
}

int main()
{
    int i, j;
    while (scanf("%d", &n) != EOF)
    {
        //输入
        for (i = 1; i <= n; i++)
        {
            scanf("%s", B[i].name);
            for (j = 1; j <= n; j++)
            {
                scanf("%s", B[i].Love[j]);
            }
        }
        for (i = 1; i <= n; i++)
        {
            scanf("%s", G[i].name);
            for (j = 1; j <= n; j++)
            {
                scanf("%s", G[i].Love[j]);
            }
        }
        //预处理:先把所有男孩、女孩都设为没有约会的状态
        for (i = 1; i <= n; i++)
        {
            B[i].is_date = false;
            G[i].is_date = false;
        }
        //好感度排序
        BoyRank();
        GirlRank();

        GS();

        //输出
        for (i = 1; i <= n; i++)
        {
            printf("%s %s\n", B[i].name, G[man[i]].name);
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值