题意:有p门课程,n个学生,然后又p行,每行都m个编号,代表课程i【i从课程1到课程p】
被学生j选中【学生j愿意当课程i的课代表】,问能否能没门课程都有一个课代表【每个人只能选
一门课程当课代表。
思路:二分图的最大匹配,匈牙利算法模板。
注意枚举的是课程,是课程选学生,并且判断是否满足所有课程都能选到学生。
而不是枚举学生选课程【刚开始就被这个坑了下】。
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int MAXP = 105;
const int MAXN = 305;
vector<int>map[MAXP];//map[i][j]为1表示学生j选择课程i
int vis[MAXN];//学生i已经选过
int link[MAXN];//学生i选择课程link[i]
int p, n;
void init()//初始化
{
memset(link, -1, sizeof(link));
for (int i = 0; i < MAXP; i++)
{
map[i].clear();
}
}
bool find(int x)
{
for (int i = 0; i < map[x].size(); i++)//枚举该课程的所有学生
{
int u = map[x][i];//u为学生编号
if (!vis[u])//该学生没被选中
{
vis[u] = 1;//标记已选中
if (link[u] == -1 || find(link[u]))
{//如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到增广路
link[u] = x;//把x匹配给学生u
return true;
}
}
}
return false;
}
int main()
{
int t,m,s;
cin >> t;
while (t--)
{
init();//初始化
cin >> p >> n;
for (int i = 0; i < p; i++)//课程i
{
cin >> m;//选择课程i的学生数目
for (int j = 0; j < m; j++)
{
cin >> s;//学生编号
map[i].push_back(s);
}
}
int ans = 0;
for (int i = 0; i < p; i++)//注意枚举的是课程,不是学生!
{
memset(vis, 0, sizeof(vis));
if (find(i))//如果所以课程能选到课代表
{
ans++;
}
}
if (ans == p)//如果所以课程都能选到课代表
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}