http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1140
这题求解的是二分图的最大匹配,只要匹配住可以"盖住"每门课程,即匹配数与课程数量相等,委员会就可以成立。在这里集合课程中的元素是相互独立的,学生集合中的元素也是相互独立的,因而判定这个是二分图。然后采用二分图的匈牙利算法即可。
代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAXN 301
int p ;
int n ;
bool course[MAXN][MAXN] ;//标记课程与学生之间的关系
bool used[MAXN] ;//标记是否访问
int match[MAXN] ;//记录之间的匹配情况
bool dfs(int ) ;
int maxmatch() ;
int main()
{
int i ;
int j ;
int num ;
int t ;
int test ;
//freopen("in.txt" , "r" , stdin) ;
scanf("%d" , &test) ;
while(test--)
{
scanf("%d%d" ,&p , &n) ;
memset(course , 0 , sizeof(course)) ;
for( i = 1 ; i <= p ; i ++)
{
scanf("%d" , &num) ;
for(j = 0 ; j < num ; j ++)
{
scanf("%d" , &t) ;
course[i][t] = 1 ;
}
}
if(maxmatch()==p)
printf("YES\n") ;
else
printf("NO\n") ;
}
return 0;
}
//求解二分图的最大匹配
int maxmatch()
{
int i ;
int matchnum = 0;
memset(match , -1 , sizeof(match));
for(i = 1 ; i <= p ; i ++)
{
memset(used , 0 , sizeof(used)) ;
if(dfs(i))
matchnum ++ ;//累加匹配数
if(matchnum == p)
break ;
}
return matchnum ;//返回最大匹配数
}
bool dfs(int k)//dfs增广
{
int i ;
int temp ;
for(i = 1 ; i <= n ; i ++)
{
//考虑学生集合中的所有元素,也即全部顶点
if(course[k][i] && !used[i])//i与k邻接并且为访问过,
{
used[i] = 1 ;
temp = match[i] ;
match[i] = k ;
//如果顶点i没匹配或者i已经匹配,但可以从match[i]出发可以找到一条增广路
if(temp==-1 || dfs(temp))
return 1 ;
match[i] = temp ;
}
}
return 0 ;
}