7.12.1 Courses

任务描述

现在有N位同学和P门课程。每位同学可以选修零门、一门或多门课程。请您确定,是否可以成立一个恰好由P位同学组成,同时又满足以下条件的委员会:

  • 在委员会中,每位同学担任一门不同课程的课代表(如果他/她选修了某门课程,则该同学可以担任该门课程的课代表);
  • 每一门课在委员会中都有一名课代表。

编程要求

根据提示,在右侧编辑器补充代码。

输入说明

程序从输入中读取测试用例。输入的第一行给出测试用例的数目。每个测试用例的格式如下: P N Count1 Student1 1 Student1 2 ... Student1 Count1 Count2 Student2 1 Student2 2 ... Student2 Count2 ...... CountP StudentP 1 StudentP 2 ... StudentP CountP 每个测试用例的第一行给出两个正整数,正整数之间由一个空格分隔:P(1<=P<=100)表示课程数,N(1<=N<=300)表示学生数。接下来的P行按课程顺序描述,从课程1到课程P,每一行描述一门课程。课程 i 的描述是在一行中首先给出整数Counti(0<=Counti<=N),表示选修课程 i 的学生数;然后,在一个空格之后,给出选修这门课程的Counti位同学,每两个连续值之间由一个空格分隔。用从 1N 的正整数对同学们进行编号。 在连续的测试用例之间没有空行。输入的数据是正确的。

输出说明

对于运算的结果,标准输出。对于每个测试用例,如果可以组成委员会,则在一行上输出“YES”,否则输出“NO”。行的开始不能有任何的前导空格。

测试说明

平台会对你编写的代码进行测试:

测试输入: 2 3 3 3 1 2 3 2 1 2 1 1 3 3 2 1 3 2 1 3 1 1 预期输出: YES NO

#include <iostream>
#include <memory.h>
using namespace std;
int a[110][310];             //二分图的相邻矩阵
int n,m,vis[310],pre[310];   //课程数n,学生数m,节点i的访问标志为vis[i],其关联的匹配边为(pre[i],i)
bool dfs(int x)              //判断以课程集合中的节点i为起点的增广路是否存在
{
    int t;
    for(t=1;t<=m;++t)         //搜索学生集合中的每个节点t
    
        if(a[x][t]&&!vis[t])  //若x和t间有边相连且t未被访问
        {
            vis[t]=1;         //访问节点t
            if(pre[t]==0||dfs(pre[t])) //若t的前驱是未盖点或者存在由t的前驱出发的可增广路,则设定(x,t)为匹配边,返回成功标志
            {
                pre[t]=x;
                return true;
            }
        }
        return false;          //返回失败标志
    
}
 int main()
    {
        int T,i,t,j,s;
        scanf("%d",&T);        //输入测试用例数
        while(T--)             //依次处理每个测试用例
        {
            scanf("%d%d",&n,&m);  //输入课程数n和学生数m
            memset(a,0,sizeof(a)); //二分图的相邻矩阵初始化
            memset(pre,0,sizeof(pre)); //初始时所有节点为未盖点
            for(i=1;i<=n;++i)  //构造二分图:搜索课程集的每个节点
            {
                scanf("%d",&j); //输入选择课程i的学生数j
                while(j--)
                {
                    scanf("%d",&t); //依次输入选择课程i的每个学生t
                    a[i][t]=1;      //i和t相连为一条边
                }
            }
            for(i=1,s=0;i<=n;++i)   //搜索课程集的每个节点i,匹配数s初始化为0
            {
                memset(vis,0,sizeof(vis)); //初始时所有节点未访问
                if(dfs(i))                 //若节点i被匹配边覆盖,则匹配边数=1
                s++;
            }
            if(s==n)printf("YES\n");       //若最大匹配数为课程数,则可组成委员会,否则失败
            else printf("NO\n");

        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值