POJ 1469 COURSES【匈牙利算法入门 二分图的最大匹配 模板题】

题目链接: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. 

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

题意:每门课对应选出一位课代表。

      当前课程的课代表必须是这门课程的学生,而且每人只可当一门课程的代表。

算法:二分图的最大匹配【模板题】

分析:分别以课程和学生为点集uv,对应匹配。

//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;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值