ZOJ 1023 University Entrace Examination(稳定匹配变形)





这道题和最标准的稳定匹配不同的,就是男和女不是一个配一个,学生可能一个学校都不能去,但一个学校却有可能录取多个学生,其他都一样。所以原来的模板,只需要改动woman数组,就是这个程序中的Woman数组。为了方便,把学生看成男,把学校看成女,那么Woman数组中对于每一个女性,都要保存目前所选的学生,不断更新。这道题除了要求稳定性,还有一个隐含的要求就是不能够再找出一组男女搭配,加入到答案中还是不会出现私奔的情况。那么假设算法结束后,现在一个男性单身,他可以再找到一个女性组成这样的搭配,这个男性已经向所有的女性告白过了,包括现在将要和他搭配的女性,那么当时这个女人拒绝他就是因为名额已经满了并且都比他好,所以这个女性一定是没法和他在一起的,假设不成立。

关于cmp函数的写法要注意,return a > b就是降序排列,return a < b就是升序排列。
一般此类题都要写成结构体形式,然后有些时候每个人要自带一个编号,避免排序以后将顺序打乱。
这道题还有一个vis数组,在这题中Man出现0是允许的,只有在所有的男性都把女性告白一遍以后才停止。





#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<cmath>
#include<algorithm>
#define N 200
using namespace std;
struct node
{
    int region;
    int score;
    int num;
    int sum;
    int like[N];
}man[N];
struct node2
{
    int region;
    int c;
}woman[N];
int T, n, m, flag, f, womanpos, y, r, maxx, numm;
int ranke[N][N], ranks[N][N], tmpman[N], cnt[N], Man[N], Woman[N][N], vis[N];
bool cmp(node a, node b)
{
    if (a.region == r && b.region == r || a.region != r && b.region != r)
    {
        return a.score > b.score;
    }
    else
        if (a.region == r && b.region != r)
        {
            return a.score > b.score*0.7;
        }
        else
            {
                return a.score*0.7 > b.score;
            }
}
bool cmp2(node a, node b)
{
    return a.num < b.num;
}
void sortrank()
{
    memset(ranks, 0, sizeof(ranks));
    memset(ranke, 0, sizeof(ranke));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= man[i].sum; j++)
        ranks[i][j] = man[i].like[j];
    for (int i = 1; i <= m; i++)
    {
        r = woman[i].region;
        sort(man+1, man+n+1, cmp);
        for (int j = 1; j <= n; j++)
            ranke[i][man[j].num] = j;
    }
}
void GS()
{
    memset(Man, 0, sizeof(Man));
    memset(Woman, 0, sizeof(Woman));
    memset(cnt, 0, sizeof(cnt));
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++) tmpman[i] = 1;
    sort(man+1, man+n+1, cmp2);
    flag = 1;
    while (flag)
    {
        flag = 0;
        for (int i = 1; i <= n; i++)
            if (Man[i] == 0 && vis[i] == 0)
            {
                flag = 1;
                if (tmpman[i] > man[i].sum)
                {
                    vis[i] = 1;
                    continue;
                }
                womanpos = ranks[i][tmpman[i]];
                if (cnt[womanpos] < woman[womanpos].c)
                {
                    cnt[womanpos]++;
                    Woman[womanpos][cnt[womanpos]] = i;
                    tmpman[i]++;
                    Man[i] = womanpos;
                }
                else
                {
                    maxx = ranke[womanpos][i];
                    f = 0;
                    for (int j = 1; j <= cnt[womanpos]; j++)
                    {
                        if (ranke[womanpos][Woman[womanpos][j]] > maxx)
                        {
                            f = 1;
                            maxx = ranke[womanpos][Woman[womanpos][j]];
                            numm = j;
                        }
                    }
                    if (f == 1)
                    {
                        y = Woman[womanpos][numm];
                        Woman[womanpos][numm] = i;
                        Man[y] = 0;
                        Man[i] = womanpos;
                        tmpman[i]++;
                    }
                    else
                        tmpman[i]++;
                }
            }
    }
}
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            man[i].num = i;
            scanf("%d%d%d", &man[i].region, &man[i].score, &man[i].sum);
            for (int j = 1; j <= man[i].sum; j++)
                scanf("%d", &man[i].like[j]);
        }
        for (int i = 1; i <= m; i++)
            scanf("%d%d", &woman[i].region, &woman[i].c);
        sortrank();
        GS();
        for (int i = 1; i <= n; i++)
            if (vis[i] == 1)
            printf("not accepted\n");
                else printf("%d\n", Man[i]);
        if (T) printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值