poj 1469 COURSES

// poj4 1469 COURSES
// 题意: 现在有p门课程和n个学生,给出每门课程都有哪些学生可以参加.
// 问能否找到p个学生,满足每个学生代表一门课程而且每门课程只由一个学生代表
// 思路:求解二分图的最大匹配数,看与p是否相等

#include<iostream> //二分图的最大匹配
#include<cstring>
using namespace std;
int p,n;
int link[305]; // link[ b ] = a 表示 V2中的点b 与 V1中的点a 相匹配
int edge[105][305],vis[305];
// edge[a][b]=1表示V1中的a节点与V2中的b节点有边相连,vis记录V2中的点是否被访问过

int find(int a) //寻找有没有从V1中的点a开始的增广轨
{
for(int i=1;i<=n;++i)
{
if(edge[a][i]&&!vis[i]) //V2中节点i与a有边相连并且节点i未被访问过
{
vis[i]=1;
if( link[i]==0 || find(link[i]) )
{
link[i]=a;
return 1;
}
//如果V2中节点i未在前一个匹配M中
//或者V2中节点i已经在匹配M中,而与V2节点i匹配的在V1中的节点,从它出发找到了增广路
//则说明找到了从V1中的点a开始的增广轨
}
}
return 0;
}
int main()
{
int cases;
scanf("%d",&cases);
while(cases--)
{
memset(edge,0,sizeof(edge)); // 节点下标从1开始
memset(link,0,sizeof(link));
scanf("%d%d",&p,&n);
int m,t;
for(int i=1;i<=p;++i)
{
scanf("%d",&m);
while(m--)
{
scanf("%d",&t);
edge[i][t]=1;
}
}
int ans=0; // 二分图的最大匹配数
for(int i=1;i<=p;++i)
{
memset(vis,0,sizeof(vis)); //清空上次搜索时的标记
if(find(i)) //从V1中节点i尝试扩展
ans++;
}
if(ans==p)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}

posted on 2011-07-22 14:52  sysu_mjc  阅读(115)  评论(0编辑  收藏  举报

导航