[wikioi2930]填报志愿(裸题)

填报志愿

  • 题目描述 Description
    高考已经结束,而志愿填报正在进行中~
    吴校长的学校里有n位同学,每位同学有ki个愿意去的大学。而在吴老师的省份中,有m所大学有招生名额。根据往年的经验,对于每所大学(编号为ci),学校中最多只会有一人考上。因此为了避免志愿冲突,每年吴校长都要安排老师对同学们的志愿进行调整。
    今年吴校长找到了你来帮忙,请你编程计算,在不冲突的情况下,最多能有多少同学顺利填报志愿,填报志愿的方案又是怎样的。

输入描述 Input Description
第一行,一个数n。

接下来的n行,每行的第一个数为ki,接下来有ki个数,表示第i个同学愿意去的大学的编号。

下一行,一个数m。 

下一行,m个数,为m个大学的编号。保证大学编号递增。

输出描述 Output Description
第一行,一个数,为在不冲突的情况下,最多能有多少同学顺利填报志愿。

接下来的若干行,输出填报志愿的方案。每行两个数,第一个数为学生编号,第二个数为大学编号,以空格隔开。若有多种可行方案,输出字典序最小的一种。

样例输入 Sample Input
3

2 1 2

3 2 4 5

2 2 3

5

1 3 4 5 6

样例输出 Sample Output
3

1 1

2 4

3 3

数据范围及提示 Data Size & Hint
0 < n<=1000, 0< ki<=20, 0 < m<=2000, 学生的编号为1~n, 大学的编号为1~5000。同学愿意去的大学不一定招生。

又是一道裸的二分图匹配,可以练练手。

#include <cstdio>
#include <cstring>
#define MAXN 1005
using namespace std;
int g[MAXN * 5][MAXN * 5], b[MAXN * 5];
int link[MAXN * 5], num[MAXN * 5];
int n, m;
int ans = 0;
int find(int x)
{
    for (int j = 1; j <= m; ++j)
    {
        int y = num[j];
        if (b[y] == 0 && g[x][y] == 1)
        {
            b[y] = 1;
            if (link[y] == 0 || find(link[y]) == 1)
            {
                link[y] = x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int t;
    memset(g, 0, sizeof(g));
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &t);
        for (int j = 1; j <= t; ++j)
        {
            int y;
            scanf("%d", &y);
            g[i][y] = 1;
        }
    }
    scanf("%d", &m); 
    for (int i = 1; i <= m; ++i)
        scanf("%d", &num[i]);
    for (int i = 1; i <= n; ++i)
    {
        memset(b, 0, sizeof(b));
        ans = ans + find(i);
    }
    printf("%d\n", ans);
    return 0;
}

谢谢大家

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值