BZOJ 1688: Disease Manangement (子集枚举)
2015-07-29 15:48
495 查看
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两类
题解:
这个题,枚举子集,真想说一句我真是日了狗了,搜集了一上午二进制法生成子集的东西才明白一点,现在算是会用一点了,简单介绍一下
这道题的的奶牛个数较小只有0-15,所以采用二进制的方法
生成子集的二进制法:二进制中只有0和1两个数字。用二进制表示子集,从右到左第i位表示元素i是否在集合中。
然后好对集合进行操作,通过为运算符实现,二元位运算:与(&),或(|),非(!)对应的是集合的交,或和对称差。
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; }
相关文章推荐
- 我们为什么选择了Cassandra而没有用Hbase
- Android 动态增加按钮 居于textview右侧
- ffmpeg高深莫测
- Apache Traffic Server 认知
- SeekBar
- SPOJ 1771 NQUEEN Yet Another N-Queen Problem
- Java包行业命名规则习惯
- db2统计表的数量及每个表的记录数
- object入门(转)
- O - 覆盖的面积 - hdu 1255(求面积)
- OC特有语法—SEL
- *POJ 3728 - The merchant(LCA‘ Tarjan)
- 鼠标悬浮标签显示提示内容
- PAT (Advanced Level) 1073. Scientific Notation (20) 科学计数法
- hdu 5313 Bipartite Graph
- POJ 题目3252 Round Numbers(组合数学)
- HDU 5319 Painter(枚举)
- 【推荐看】什么时候用C而不用C++?
- 使用 Apache Solr 实现更加灵巧的搜索,第 1 部分: 基本特性和 Solr 模式
- c#系列——“OSGeo.GDAL.GdalPINVOKE”的类型初始值设定项引发异常。