标签:分组 main can const scanf ons class nbsp std
题解:
第一个状压dp题.所以写仔细些
题目转化为:
有n个集合进行分组,求最多满足条件的分组数
状态是:n个集合,每个集合选可或不选。共1<<n种情况
根据二进制,可以由前向后递推 f[s]=max(f[s-s0])+1, s0是s的子集,cover[s0]等于全集
子集枚举:
for (int x = S; x; x = (x-1)&S)
解释
http://www.cnblogs.com/jffifa/archive/2012/01/16/2323999.html
(x-1)&s把s中的0全部忽略,并不断减1的结果
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1<<17; int n,m,x,all,Case=1; int cover[maxn],f[maxn],p[17]; int main() { while(~scanf("%d",&n)&&n) { for(int i=0;i<n;i++) { p[i]=1<<i; scanf("%d",&m); while(m--) { scanf("%d",&x); p[i]|=(1<<x);//将每个点以及相邻的点的集合用二进制表示,一共有n个点,所以有n个集合 } } all=(1<<n)-1; for(int s=0;s<(1<<n);s++) { cover[s]=0; for(int i=0;i<n;i++) { if(s&(1<<i)) cover[s]|=p[i];//s表示选取的那几个集合的二进制和,cover[s]表示选取这些集合覆盖了多少点,二进制表示 } } for(int s=0;s<(1<<n);s++) { f[s]=0; for(int s0=s;s0;s0=(s0-1)&s)//s0为s的子集 { if(cover[s0]==all) f[s]=max(f[s],f[s^s0]+1); } } printf("Case %d: %d\n",Case++,f[all]); } return 0; }
标签:分组 main can const scanf ons class nbsp std
原文地址:http://www.cnblogs.com/byene/p/6001468.html