题目链接:http://poj.org/problem?id=1469
COURSES
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 14455 | Accepted: 5715 |
Description
Consider a group of N students and P courses. Each student visits zero, one or more than one courses. Your task is to determine whether it is possible to form a committee of exactly P students that satisfies simultaneously the conditions:
- every student in the committee represents a different course (a student can represent a course if he/she visits that course)
- each course has a representative in the committee
Input
Your program should read sets of data from the std input. The first line of the input contains the number of the data sets. Each data set is presented in the following format:
P N
Count1 Student 1 1 Student 1 2 ... Student 1 Count1
Count2 Student 2 1 Student 2 2 ... Student 2 Count2
...
CountP Student P 1 Student P 2 ... Student P CountP
The first line in each data set contains two positive integers separated by one blank: P (1 <= P <= 100) - the number of courses and N (1 <= N <= 300) - the number of students. The next P lines describe in sequence of the courses �from course 1 to course P, each line describing a course. The description of course i is a line that starts with an integer Count i (0 <= Count i <= N) representing the number of students visiting course i. Next, after a blank, you抣l find the Count i students, visiting the course, each two consecutive separated by one blank. Students are numbered with the positive integers from 1 to N.
There are no blank lines between consecutive sets of data. Input data are correct.
P N
Count1 Student 1 1 Student 1 2 ... Student 1 Count1
Count2 Student 2 1 Student 2 2 ... Student 2 Count2
...
CountP Student P 1 Student P 2 ... Student P CountP
The first line in each data set contains two positive integers separated by one blank: P (1 <= P <= 100) - the number of courses and N (1 <= N <= 300) - the number of students. The next P lines describe in sequence of the courses �from course 1 to course P, each line describing a course. The description of course i is a line that starts with an integer Count i (0 <= Count i <= N) representing the number of students visiting course i. Next, after a blank, you抣l find the Count i students, visiting the course, each two consecutive separated by one blank. Students are numbered with the positive integers from 1 to N.
There are no blank lines between consecutive sets of data. Input data are correct.
Output
The result of the program is on the standard output. For each input data set the program prints on a single line "YES" if it is possible to form a committee and "NO" otherwise. There should not be any leading blanks at the start of the line.
Sample Input
2 3 3 3 1 2 3 2 1 2 1 1 3 3 2 1 3 2 1 3 1 1
Sample Output
YES NO
Source
题意:每门课对应选出一位课代表。
当前课程的课代表必须是这门课程的学生,而且每人只可当一门课程的代表。
算法:二分图的最大匹配【模板题】
分析:分别以课程和学生为点集u、v,对应匹配。
//00K 438MS C++ 1003B
#include<cstdio>
#include<cstring>
const int maxN=310;
const int maxP=110;
int map[maxP][maxN];//建图
int match[maxN];//匹配连接
bool vis[maxN];//标记
int uN,vN;
bool dfs(int u)
{
for(int v=1;v<=vN;v++)//对应遍历学生
{
if(!vis[v] && map[u][v])
{
vis[v]=true;
if(match[v]==-1 || dfs(match[v]))
{
match[v]=u;
return true;
}
}
}
return false;
}
bool hungary()
{
int sum=0;
memset(match,-1,sizeof(match));//未匹配前,初始化
for(int i=1;i<=uN;i++)//遍历每一门课程
{
memset(vis,false,sizeof(vis));//找增广路前初始化
if(dfs(i)) sum++;
}
if(sum==uN) return true;
else return false;
}
int main()
{
int test;
int p,n;
int num_stu,student;
while(scanf("%d",&test)!=EOF)
{
while(test--)
{
scanf("%d%d",&p,&n);
uN=p,vN=n;
memset(map,0,sizeof(map));
for(int i=1;i<=p;i++)
{
scanf("%d",&num_stu);//选这门课的学生人数
for(int j=1;j<=num_stu;j++)
{
scanf("%d",&student);
map[i][student]=1;
}
}
if(hungary()) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
//300K 438MS C++ 1465B
//PS:初次做这种题目时分析的代码。和上面的差不多
#include<stdio.h>
#include<string.h>
int link[310];
int n,m;
int v[310];
int map[110][310];
bool find(int x)
{
int i;
for(i=1;i<=m;i++)//从第一个人开始查找,把第x节课分配给第i个人
{
if(!v[i] && map[x][i])//如果第i个人没有被分配课程,并且第i个人选了第x节课
{
v[i]=1;//第i个人标记为分配了课程
if(link[i]==0 || find(link[i]))//如果这门课程没有被分配掉
{ //或者假如这门课被分配掉了。。然后你看分配的这个学生能不能找到其他选择,有其它选择就把这门课空出来那这个人就可以选了。。
link[i]=x;//标记这门课被选,第i个人选了第x节课
return true;
}
}
}
return false;
}
int main()
{
int test;
int i,j;
int x,y;
int sum;
scanf("%d",&test);
while(test--)
{
sum=0;
memset(map,0,sizeof(map));
memset(link,0,sizeof(link));
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&x);
for(j=1;j<=x;j++)
{
scanf("%d",&y);
map[i][y]=1;//第y个人可以选第i节课 ,就是加一条i到y的有向边
}
}
for(i=1;i<=n;i++)//从第一节课开始分配每一节课
{
memset(v,false,sizeof(v));
if(find(i))//寻找最大匹配。最大匹配就是要不停地找增广路,所以每次都要初始化,重新再找直到找不到了
sum++;
}
if(sum==n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}