#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> #include <queue> #include <vector> using namespace std; const int maxe = 50000; const int maxn = 17; const int INF = 0x3f3f3f; int main() { // freopen("E:\\acm\\input.txt","r",stdin); int N; int dp[1<<maxn],cover[1<<maxn]; int P[1<<maxn]; int cas=0; while(cin>>N && N){ for(int i=0;i<N;i++){ int m,x; cin>>m; P[i] = 1<<i; while(m--) cin>>x, P[i] |= (1<<x); } for(int S=0; S < (1<<N); S++){ cover[S] = 0; //集合S所覆盖的点集; for(int i=0;i<N;i++){ if(S & (1<<i)) cover[S] |= P[i]; } } dp[0] = 0; int ALL = (1<<N) - 1; for(int S=1;S<(1<<N);S++){ dp[S] = 0; for(int S0=S;S0;S0=(S0-1)&S) //枚举S的子集。(S0-1)&S可以这样看:假如S,S0的二进制位都为1011001,则S0-1就为1011000,在与S取交集,就得1011000,就是我们想要的S的子集。依次类推。 if(cover[S0] == ALL) dp[S] = max(dp[S],dp[S^S0] + 1); //S^S0是S0在全集S下的补集。 } printf("Case %d: %d\n",++cas,dp[ALL]); } }