# Disease Manangement

Q - 枚举子集
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

Alas! A set of D (1 <= D <= 15) diseases (numbered 1..D) is running through the farm. Farmer John would like to milk as many of his N (1 <= N <= 1,000) cows as possible. If the milked cows carry more than K (1 <= K <= D) different diseases among them, then the milk will be too contaminated and will have to be discarded in its entirety. Please help determine the largest number of cows FJ can milk without having to discard the milk.

Input

* Line 1: Three space-separated integers: N, D, and K

* Lines 2..N+1: Line i+1 describes the diseases of cow i with a list of 1 or more space-separated integers. The first integer, d_i, is the count of cow i's diseases; the next d_i integers enumerate the actual diseases. Of course, the list is empty if d_i is 0.

Output

* Line 1: M, the maximum number of cows which can be milked.

Sample Input

6 3 2
0
1 1
1 2
1 3
2 2 1
2 2 1


Sample Output

5


Hint

OUTPUT DETAILS:

If FJ milks cows 1, 2, 3, 5, and 6, then the milk will have only two diseases (#1 and #2), which is no greater than K (2).

有N头牛,它们可能患有D种病,现在从这些牛中选出若干头来,但选出来的牛患病的集合中不过超过K种病.
6 3 2    N,D，k
0        第一列是奶牛携带的疾病个数，后面表示疾病的种类
1 1
1 2
1 3
2 2 1
2 2 1    携带两种疾病，种类为1，2两类

然后好对集合进行操作，通过为运算符实现，二元位运算：与（&），或（|），非（！）对应的是集合的交，或和对称差。

x&=(x-1)表示将x转化为2进制，最低的为1的位变成0，看含有的1的个数。

这是“位运算”中的一种很经典的用法，“&”是“与”的意思。它具体点的意思就是把x的二进制表示数最右边的一个1变成0  例如：
e1:
x      = 01001000
x-1    = 01000111
x&(x-1)= 01000000
e2:
x      = 01001001
x-1    = 01001000
x&(x-1)= 01001000
可见只有前后x与x-1中的两个运算数都是 1 的时候结果才是1.同理“|”运算也是两个运算数有一个为1就是1.具体解释在代码中AC代码：
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,d,k;
int N[1000+5];
bool judge(int x)
{
int c=0;
while(x)
{
c++;              // 将x转化为2进制，看含有的1的个数。
x&=(x-1);         //将最低的为1的位变成0
}
if(c<=k)              //限制个数
return 1;
else
return 0;
}
int main()
{
int s,t,total=0;
scanf("%d%d%d",&n,&d,&k);
for(int i=0; i<n; i++)
{
cin>>s;
for(int j=0; j<s; j++)
{
cin>>t;
N[i]|=1<<(t-1); //1<<t-1（1的二进制数整体向左移t-1位）
//一起把二进制数的位数对应着来看，这两个数在这一位上有1的结果就是1，否则是0

}
}
for(int i=0; i<(1<<d); i++)  //i<(1<<d)是当i不小于（1左移d位的数）时终止循环，枚举各子集对应的编码0,1,2,..2^d-1
{
if(judge(i))
{
int f=0;
for(int j=0; j<n; j++)
{
if((N[j]|i)==i) f++;  //对应N[j]与i的并集与i相等，说明N[j]是它的子集
}
if(f>total)
total=f;
}
}
cout<<total<<endl;
return 0;
}

posted @ 2015-07-29 15:48  hfcnal  阅读(325)  评论(0编辑  收藏  举报