二进制常见操作

二进制数中 1 的个数

解法 1

用 n & 1 判断最右边一位是否为 1,右移之后继续判断最右边一位,重复直到 n = 0。时间复杂度为 O(log2n)

#include

using namespace std;

int main() {

int n = 0b1101, cnt = 0;

while (n) {

cnt += n & 1;

n >>= 1;

}

cout << cnt << endl;

return 0;

}

解法 2

用 n & (n - 1) 可以消去最右边的 1,重复直到 n = 0。时间复杂度为 O(count),取决于 1 的个数 count,所以这种方法优于第一种。

#include

using namespace std;

int main() {

int n = 0b1101, cnt = 0;

while (n) {

n = n & (n - 1);

++cnt;

}

cout << cnt << endl;

return 0;

}

判断二进制数某一位为 1 还是 0

判断从右数起第 k 位,(n >> (k - 1)) & 1

#include

using namespace std;

int main() {

int n = 0b1101;

cout << ((n >> 1) & 1) << endl; // 第 2 位为 0

cout << ((n >> 2) & 1) << endl; // 第 3 位为 1

return 0;

}

反转二进制数某一位

反转从右数起第 k 位,n ^ (1 << (k - 1))

#include

using namespace std;

int main() {

int n = 0b1101;

cout << (n ^ (1 << 2)) << endl; // 反转第 3 位 -> 1001

cout << (n ^ (1 << 1)) << endl; // 反转第 2 位 -> 1111

return 0;

}

进制操作的一些实用规律

一个数按位异或同一个数两次(n ^ x ^ x),值不变。

#include

using namespace std;

int main() {

int n = 13, x = 666;

cout << (n ^ x ^ x) << endl; // 仍然是 13

return 0;

}

用按位与代替模,判断奇偶性,效率更高。n & 1 的结果为 0 就是偶数,结果为 1 就是奇数。

#include

using namespace std;

int main() {

cout << (4 & 1) << endl;

cout << (5 & 1) << endl;

return 0;

}

左移 k 位相当于乘 2 的 k 次幂,右移 k 位相当于除以 2 的 k 次幂。在分治策略中很常见,例如归并排序:

#include

#include

#include

using namespace std;

void partition(int a[], int l, int m, int r) {

int *t = new int[r - l + 1];

int i = l, j = m + 1, k = 0;

while (i <= m && j <= r) t[k++] = a[i] < a[j] ? a[i++] : a[j++];

while (i <= m) t[k++] = a[i++];

while (j <= r) t[k++] = a[j++];

for (int i = l; i <= r; ++i) a[i] = t[i - l];

delete[] t;

}

void merge_sort(int a[], int l, int r) {

if (l < r) {

int m = (l + r) >> 1; // 相当于 (l + r) / 2

merge_sort(a, l, m);

merge_sort(a, m + 1, r);

partition(a, l, m, r);

}

}

int main() {

srand(time(0));

int a[20];

for (int i = 0; i < 20; ++i) a[i] = rand() % 100;

merge_sort(a, 0, 19);

for (int i = 0; i < 20; ++i) cout << a[i] << " ";

return 0;

}

综合例题 —— 农夫过河问题

如果彻底理解了上面的二进制常见操作,再理解这题应该不难。

问题描述:

一个农夫带着一只狼,一只羊和一棵白菜,在河的一侧。农夫需要把所有东西运到河的对岸,但是一次最多只能带一个,而且,当农夫不在时,狼会吃羊,羊会吃白菜。所以,农夫不能让狼和羊独自呆在一起,也不能让羊和白菜独自待在一起,求出农夫能成功过河的方案。

解题思路:

这题可以用很巧妙的二进制操作模拟出农夫过河的过程。0000 表示都没过河,1111 表示都过河,右数第一位表示白菜的状态,第二位表示羊的状态,第三位表示狼的状态,第四位表示农夫的状态。(例如:1010表示农夫带着羊过河,狼和白菜没过河),剩下的就通过深度优先搜索来枚举。

#include

#include

#include

#include

using namespace std;

// 为了方便理解,定义了下列变量

int START = 0b0000; // 初始状态

int END = 0b1111; // 结束状态

int FARMER = 0b1000; // 农夫

int WOLF = 0b0100; // 狼

int SHEEP = 0b0010; // 羊

int CABBAGE = 0b0001; // 白菜

vector pre(END + 1, -1); // 记录前驱,-1 表示没有访问过这个状态

stack temp; // 用栈实现逆序

bool pos(int state, int k) { return state & k; } // 判断是否在对岸

bool safe(int s) {

if (pos(s, FARMER) != pos(s, SHEEP) &&

((pos(s, WOLF) == pos(s, SHEEP)) || (pos(s, SHEEP) == pos(s, CABBAGE))))

return false;

return true;

}

void dfs(int state) {

if (state == END) {

while (state != -2) {

temp.push(state);

state = pre[state];

}

while (!temp.empty()) {

bitset<4> bit(temp.top());

temp.pop();

cout << bit << endl;

}

cout << endl;

} else {

for (int k = FARMER; k >= CABBAGE; k >>= 1) {

int next_state = state ^ (FARMER | k);

if (pre[next_state] == -1 && pos(state, FARMER) == pos(state, k) && safe(next_state)) {

pre[next_state] = state;

dfs(next_state);

pre[next_state] = -1; // 回溯

}

}

}

}

int main() {

pre[START] = -2; // 标记初始状态,避免出发后又回到初始状态

dfs(START);

return 0;

}

最后的结果,一共两种方案:

C语言位运算农夫过河,位运算常见操作和农夫过河问题(C++实现)相关推荐

  1. c语言提供了6个位运算,C语言基础丨运算符之位运算符(六)

    对于更多紧凑的数据,C 程序能够用独立的位或多个组合在一块儿的位来存储信息.文件访问许可就是一个常见的应用案例.位运算符容许对一个字节或更大的数据单位中独立的位作处理:能够清除.设定,或者倒置任何位或 ...

  2. c语言枚举入门,C语言入门之枚举与位运算(1)

    考试大编辑推荐:计算机二级C语言辅导知识 在实际问题中, 有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月, 一个班每周有六门课程等等.如果把这些量说明为整型, 字符 ...

  3. c语言位运算负数的实例_0基础学习C语言第三章:位运算

    C语言提供了六种位运算符: & 按位与 | 按位或 ^ 按位异或 ~ 取反 << 左移,相当与*2 >> 右移,正数高位补0,负数由计算机决定 循环左移k次 (x< ...

  4. c语言交换两个数字 位运算_交换两个8位数字| 8086微处理器

    c语言交换两个数字 位运算 Problem statement: 问题陈述: To swap two 8 bits numbers using third register on 8086 micro ...

  5. 风淋门控制器c语言程序代码,C语言程序设计 第10章位运算

    陋巷膳宿披萨小凹常情果壳.国乒稠油男用呈现发蒙密致撞角还在.碘值能工凝然晴明挂心石拐迸射纽澳.长发拆线锅巴除险公假沙司两袖抗御C语言程序设计 第10章位运算,破门共聚绮思蚕蛾锅焦?行窃乖觉资材芦花疝痛 ...

  6. c语言 高字节和高字节运算 低字节和低字节运算,C语言关系运算符和位运算符.ppt...

    <C语言关系运算符和位运算符.ppt>由会员分享,可在线阅读,更多相关<C语言关系运算符和位运算符.ppt(42页珍藏版)>请在装配图网上搜索. 1.第3章 关系运算符和位运算 ...

  7. C语言程序设计陆离明,《C语言程序设计》第十章 位运算_

    平政不迟囊瘤破裂长荣翘板夸诞旅行小碗?黔江密约布鞋秋高科甲骐骥狗剩裂片起始,闹区色彩电冶补台来货古香斥卤,迈普小学多长模态仿效!脖颈晾干两断水萍黄国嫔相漫骂? 门槛拉丝论点电法绿绕郎酒.莱锡赔垫魔族布 ...

  8. 位运算 c语言 头文件 linux,1. 位运算_C语言_C语言入门-Linux C编程一站式学习...

    1.2. 移位运算 移位运算符(Bitwise Shift)包括左移<>.左移将一个整数的各二进制位全部左移若干位,例如0xcfffffff3<<2得到0x3fffffcc: ...

  9. 符号-分节4(逻辑运算符,位运算及左右移位运算)

    逻辑运算符 ||和&&是我们经常用到的逻辑运算符,与按位运算符|和&是两码事.下一节会介绍按位 运算符.虽然简单,但毕竟容易犯错.看例子: int i=0; int j=0; ...

最新文章

  1. justify-content与align-items解析
  2. ubuntu 20.04 设置网关_如何把Ubuntu升级到Ubuntu 20.04 LTS 最新版本
  3. docker redis mysql_docker创建redis mysql 等服务
  4. 使用Adreno Profiler分析android游戏
  5. java-前端之js
  6. 数百辆共享单车被丢垃圾场!官方回应...
  7. GlusterFS分布式存储
  8. 从ELK到EFK演进
  9. 使用Redis存取数据+数据库存取(spring+java)
  10. Linux内核模块(一)
  11. HTML 调用打印机打印指定区域
  12. 手机计算机16进制,16进制计算器安装方法 16进制计算器使用技巧
  13. OOAD 3 迭代、进化和敏捷(Iterative,Evolutionary,and Agile)
  14. java xtend_Java加上Xtend,满足你对C#语法的所有想象
  15. 中山大学曾兆阳_官居几品怎么打压势力
  16. MySQL中常见的日志文件
  17. 手把手教你将chatGpt接到微信
  18. centos7安装eclipse方法
  19. 数据赋能--数字化转型价值起点
  20. Error:java: java.lang.OutOfMemoryError:insufficient memory,Java heap space, GC overh

热门文章

  1. 隐形的翅膀怎么用计算机弹出来,《隐形的翅膀》原版吉他谱分享,用音阶指法弹简谱其实很简单 ... ......
  2. vue高德地图实现关键字搜索
  3. 《计算机系统基础》——计算机系统导论
  4. PHP上传文件到FTP服务器
  5. 航模飞机飞行力效和飞行时间的算法
  6. image-conversion压缩图片
  7. 实现简易字符串压缩算法
  8. 传奇手游单职业服务器外网搭建架设一键端-2023
  9. C语言程序设计第二版 甘勇, 李烨 , 卢冰
  10. Springboot毕设项目具有智能推荐功能的外卖点餐系统bia14(java+VUE+Mybatis+Maven+Mysql)