题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目;
思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的 +1,找出其中和最大的;就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充;
知识点:
- 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010;(怎么利用的这个特点不明白),在计算机网络中也学到,路由器在寻找目的MAC地址和MAC地址时就需要通过&运算进行计算,如果结果与目的MAC地址一样就转发;
- t |= (1 << (b - 1));表示t等于b转换成二进制后,再转换成十进制,就是或,相同为0,不同为1,在这里相当于二进制求和。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 #define maxn 1005 7 int n, d, k; 8 int cow[maxn]; 9 10 int ok(int a) 11 { 12 int ret = 0; 13 while (a) 14 { 15 ret += (a & 1); 16 a >>= 1; 17 } 18 return ret == k;///如果a转换成二进制有k个1,返回k,否则返回0 19 } 20 21 int main() 22 { 23 scanf("%d%d%d", &n, &d, &k); 24 for (int i = 0; i < n; i++) 25 { 26 int a, b; 27 scanf("%d", &a); 28 for (int j = 0; j < a; j++) 29 { 30 scanf("%d", &b); 31 cow[i] |= (1 << (b - 1)); 32 cout<<cow[i]<<endl; 33 ///cow[i]表示牛得病的2进制表示,然后转换为十进制 34 ///如果1 2的话,就是010(cow[i] = 2),第二个位置是1 35 ///如果2 1 2的话,就是011(cow[i] = 3),第一二个位置是1 36 } 37 } 38 int s = (1 << k) - 1; 39 int e = s << (d - k);///即s*(2^(d-k)) 40 int ans = 0; 41 for (int i = s; i <= e; i++) 42 { 43 if (ok(i))///如果该牛有k种病,进下一关 44 { 45 int temp = 0; 46 for (int j = 0; j < n; j++)///枚举每头牛,符合的加1 47 { 48 ///不明白if 49 if ((i & cow[j]) == cow[j])///都转化为2进制,按位与,二进制数只要小于i就满足 50 temp++; 51 } 52 ans = max(ans, temp); 53 } 54 } 55 printf("%d ", ans); 56 return 0; 57 }