状压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; }
时间: 2024-10-14 05:36:04