纠结了这道题很久,开始的时候就想到了用并查集,但是对并查集并不熟悉,所以在网上参考了[这个链接上的内容](http://www.cnblogs.com/jackge/p/3228479.html)
主要是通过一个dfs,遍历所有的可能,暴力枚举,原文是用c++写的,我改用了java写,其实都是差不多的。
思路:
1. 利用一个map二维数组记录所有对应关系。
2. 利用一个root一维数组记录所有集合的根
3. dfs开始的条件为0个人,0个球,然后通过dfs逐渐添加人数和球的个数,保证了组成的集合数与球的个数是相等的
4. 让每一个人都分别属于一个不同的集合。然后判断一个点可不可以放入一个集合里,这时候要找到那个集合的根,同时,要确保这个点不与集合里面的所有点有冲突。同时,一个点可能可以放入多个集合中,那样通过一个dfs,那样就可以枚举出所有的可能,再通过一个判断,就可以知道是否有满足题意的点。
import java.util.Scanner;
/**
* Created with IntelliJ IDEA
* Author: HWJ
* Date: 2016-08-25
* Time: 8:14
*/
public class Main {
private static int[] root ;
private static boolean[][] map;
private static boolean finish ;
private static int n,m;
public static void main(String[]Args) {
Scanner input = new Scanner(System.in);
while(input.hasNext()){
n = input.nextInt();
m = input.nextInt();
root = new int[n];
map = new boolean[n][n];
finish = false;
for(int i=0;i<n;i++){
int K = input.nextInt();
root[i] = i;
for(int j=0;j<K;j++){
int a = input.nextInt();
map[i][a] = true;
}
}
dfs(0,0);
if(n <= m || finish){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
public static void dfs(int x,int y){
if(finish) {
return;
}
if(y > m) {
return;
}
if(x == n){
finish = true;
return ;
}
for(int i=0;i<x;i++){
if(root[i] != i){
continue;
}
boolean fg = true;
for (int j=i;j<x && fg; j++){
if(root[j] == i){
fg = map[j][x];
}
}
if(fg){
root[x] = i;
dfs(x+1,y);
root[x] = x;
}
}
dfs(x+1,y+1);
}
}