/* http://acm.hdu.edu.cn/showproblem.php?pid=3006 The Number of set 位运算,没什么好说了,能想到思路,代码就很容易了,细心点就是了。 */ #include <cstdio> #include <iostream> #include <string> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define CLR(c,v) memset(c,v,sizeof(c)) const int inf = -(1<<30); const int INF = (1<<30); const int M = 2e4 + 10; template <typename _T> _T Max(_T a, _T b){ return (a>b)?(a):(b); } template <typename _T> _T Max(_T a, _T b,_T c){ return (a>Max(b,c))?(a):(Max(b,c)); } int ans; int set[110]; void solve(int goal_set,int h){ int tmp_goal = goal_set; for(int i = 0 ; i < h ; i++){ if(((~goal_set) & set[i]) == 0){ // set[i] 是不是goal_set的子集 tmp_goal &= goal_set - set[i];// 是子集则去重 } } if(tmp_goal == 0)ans++; // 是否goal_set集合中的全部元素都能由子集合中的元素构成 } int main(){ //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int h,n; // h个小集合,n为大集合元素个数 while(cin >> h >> n){ CLR(set,0); ans = 0; for (int i = 0 ; i < h ; i ++){ int l; cin >> l; for(int j = 0 ; j < l ; j++){ int element; cin >> element; set[i] |= 1<<(element-1); // 6 5 4 1 [实际输入]转换为 // 1 1 1 0 0 1 [二进制] // 6 5 4 3 2 1 [标号|下标] // 1表示这个选择了,0表示这个没有选择 } } int bound = (1<<n) - 1; // 若set.size() == n 则set的子集(不含空集)个数为(2^n)-1 for(int i = 1 ; i <= bound ; i++){ solve(i , h); } cout << ans << endl; } return 0; }