分析:一开始以为是匹配,GG,没认真读题......每个组至少有一个小球可以玩,而且每个组内不会有两个小朋友,相互不喜欢。如果A喜欢和B一起玩,则B也喜欢和A一起玩。因为数据很小 n,m,k<=10 应该直接暴力遍历一遍的。对于第x人来说,要么加入之前的小组,要么单立一个小组。因此需要遍历之前每个小组中的所有人,全部喜欢才能假如小组,否则就是单立小组。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//#define test
int n,m;
int rot[100],G[20][20]; // G[][]:二元关系 rot[]:rot[i]=j i的根是j
bool ok;
void dfs(int x,int y){ // 判断第x个人是否能够加入之前的集合中
if(ok) return;
if(x==n){ ok=true; return; }
if(y>m) return;
for(int i=0;i<x;i++){ // 遍历之前所有集合,找到集合的根
if(rot[i]!=i) continue;
int tag=1;
// 遍历此集合 如果没有不喜欢的人则加入集合
for(int j=i;j<x && tag;j++) // 因为在输入的时候把关系全部存放在了上三角形中,所以只需要遍历上三角形中的二元关系即可
if(rot[j]==i) tag=G[j][x];
if(tag){
rot[x]=i;
dfs(x+1,y);
rot[x]=x;<span style="white-space:pre"> </span>// 将该点还原,以找到下一个该点的可能落脚点,以确保可以考虑到所有的可能
}
}
dfs(x+1,y+1); // 不能加入之前所有集合 -> y+1
}
int main(){
#ifdef test
freopen("Hdu 2208 唉,可爱的小朋友 test case.txt","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF){
memset(G,0,sizeof(G));
ok=false;
for(int i=0;i<n;i++){
int k,t;
scanf("%d",&k);
rot[i]=i;
for(int j=0;j<k;j++){
scanf("%d",&t);
G[i][t]=1;
}
}
if(m>=n) printf("YES\n"); // 一开始球比人多直接yes
else{
dfs(0,0);
printf("%s",ok?"YES\n":"NO\n");
}
}
return 0;
}