状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了,
参考了 http://blog.csdn.net/nash142857/article/details/7968554
还有http://linest.iteye.com/blog/1175648
这两篇一起看了 了解了,也知道自己记忆化搜索错在哪里了,改了也A掉了
int n,m;
int dp[(1<<16) + 1];
void init() {
memset(dp,-1,sizeof(dp));
}
bool input() {
while(cin>>n>>m) {
return false;
}
return true;
}
void cal() {
int k;
int q = m;
int ss = (1<<n) - 1;
while(q--) {
int k;
scanf("%d",&k);
int s = 0;
for(int i=0;i<k;i++) {
int x;
scanf("%d",&x);
s |= (1<<(x - 1));
}
int now = ss^s;//并集减去交集,其实以1<<16为全集的,所以相当于补集
dp[s] = max(dp[s],1);//加边界
for(int i=now;i != 0;i = (i - 1)&now) {//对于补集进行枚举,然后跟原来的集合取交集
if(dp[i] != -1)
dp[s|i] = max(dp[s|i],dp[i] + 1);
}
}
int ans = -1;
for(int i=0;i<(1<<n);i++)
ans = max(dp[i],ans);
if(ans == -1)ans = 0;
cout<<ans<<endl;
}
void output() {
}
int main() {
while(true) {
init();
if(input())return 0;
cal();
output();
}
return 0;
}