POJ 2436 二进制枚举+位运算

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

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

知识点:

  1. 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010;(怎么利用的这个特点不明白);
  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\n", ans);
56     return 0;
57 }

时间: 2024-08-15 00:13:13

POJ 2436 二进制枚举+位运算的相关文章

二进制的位运算

二进制的位运算: 1.按位与 & 1)清零.如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零. 2)取数中指定位.取对应x位,该数的对应位为1,其余位为零.可以得到x位的指定位数. 2.按位或  | 1)常用来对一个数的某个位,置1. 3.异或运算 ^ 1)使特定位翻转,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可. 2)与0相异保留原值. 值交换的方法:1.借助第三变量来实现:C=A;A=B;B=C; 2.利用加减法实现两个变量

(九)二进制、位运算、位移运算符

JavaSE(九) --二进制.位运算.位移运算符 一.二进制简介 现代电子计算机全部采用的是二进制,因为它只使用0,1两个数字符号,简单方便.数字电路中,1代表高电平,2代表低电平.这样,数据的传输通过控制电平的高低就可以了.计算机内部处理信息,都是采用二进制数来表示的.二进制(Binary)数用0和1的两个数字及其组合来表示任何数,进位规则是"逢二进一",按从右至左的顺序,右低位,左高位. 二.二进制基础 1.所有的二进制数最高位代表符号位,0表示正数,1表示负数. 2.一个字节等

关于二进制以及位运算

聊到二进制以及位运算就不得不说说,原码,反码,补码了,网上对于原码反码补码的解释过于复杂,我这里把教程里的一些总结搬出来让大家参考一下:对于有符号的而言; 1.二进制最高位是符号位,0表示正数,1表示负数: 2.正数的原码反码补码都一样: 3.负数的反码等于它的原码符号位不变,其他位取反,1变0,0变1: 4.负数的补码等于它的反码+1: 5.0的反码补码都是0: 6.PHP没有无符号数: 7.在计算机运算时,都是以补码的方式来运算的: 所以当你进行位运算时,应把变量的补码求出后进行运算之后,再

二进制-高效位运算

数独 数独是介绍位运算的好例子,运用位运算和不运用效率差别还是挺大的.我们先看数独需求: 1.当前数字所在行数字均含1-9,不重复 2.当前数字所在列数字均含1-9,不重复 3.当前数字所在宫(即3x3的大格)数字均含1-9,不重复(宫,如下图每个粗线内是一个宫) . 常规算法 若是我们采用常规方式的,每填写一个数字,需要检查当前行.列,宫中其他位置是否有重复数字,极端情况下需要循环27(3*9)次来进行检查,我们看下常规算法下check int check(int sp) { // 檢查同行.

poj 3225 线段树+位运算

略复杂的一道题,首先要处理开闭区间问题,扩大两倍即可,注意输入最后要\n,初始化不能随便memset 采用线段树,对线段区间进行0,1标记表示该区间是否包含在s内U T S ← S ∪ T 即将[l,r]标记为1I T S ← S ∩ T 即将-oo~l和r~+oo标记为0,因为是并集,所以并集后的集合s一定在[l,r]内,则在l,r内的集合被标记是什么状态就是什么状态(表示是否属于s),[l,r]外的集合不属于s所以标记为0D T S ← S - T  即将[l,r]标记为0,则在[l,r]内

POJ 1166 The Clocks 位运算与BFS

1.题意:有一组3*3的只有时针的挂钟阵列,每个时钟只有0,3,6,9三种状态:对时针阵列有9种操作,每种操作只对特点的几个时钟拨一次针,即将时针顺时针波动90度,现在试求从初试状态到阵列全部指向0的状态所需要的最小操作数的操作方案: 2.输入输出:输入给出阵列初始状态,0,1,2,3分别表示0,3,6,9:要求输出最快方案的操作序列: 3.分析:IOI 1994的考题,BFS是比较容易想到的方法之一,关键是如何简洁的表示和改变BFS过程中的阵列状态:这里使用位运算的方法:具体如下: 首先一共9

POJ 2777 Count Color(位运算+线段树+lazy+区间更新)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 39905   Accepted: 12034 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

Java基础之二进制的位运算介绍

前言 Java编程思想中的操作符这个章节的第一句:在最底层,Java中的数据是通过使用操作符来做的.下面我将重点介绍位运算. 算术运算 Java语言中的基本算术操作符与其他的大多数的程序设计语言是相同的.其中包括 1.加,+ 2.减,- 3.乘,* 4.除,/ 5.取模, % 位运算 1.与 & 2.或 | 3.非 ~ 4.异或 ^ 5.左移 << 6.右移 >> 7.补零右移 >>> 参考资料 Java基本运算符 :https://www.cnblogs

二进制和位运算中的异或

1.给出一个问题:给你一个整形数组,这个数组中除了一个数字仅仅出现一次外,其它数字都仅仅出现两次,求出那个仅仅出现一次的数字? 要求:时间复杂度为O(n) , 空间复杂度为O(1). 这个题目的难点在于空间复杂度的限制. 解法:一个数出现两个,两个数同样.而相等两个数异或的值为0 . 所以.我们仅仅须要把整个数组的数都异或一遍,我们就能得到仅仅出现了一次的那个数字 <span style="font-size:18px;">int get_one_num(int num[]