POJ 2436 二进制枚举+位运算

题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目;

思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的   +1,找出其中和最大的;就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充;

知识点:

  1. 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010;(怎么利用的这个特点不明白),在计算机网络中也学到,路由器在寻找目的MAC地址和MAC地址时就需要通过&运算进行计算,如果结果与目的MAC地址一样就转发;
  2. 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 }
View Code
原文地址:https://www.cnblogs.com/ACMERY/p/4480441.html