C语言位运算农夫过河,位运算常见操作和农夫过河问题(C++实现)
二进制常见操作
二进制数中 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++实现)相关推荐
- c语言提供了6个位运算,C语言基础丨运算符之位运算符(六)
对于更多紧凑的数据,C 程序能够用独立的位或多个组合在一块儿的位来存储信息.文件访问许可就是一个常见的应用案例.位运算符容许对一个字节或更大的数据单位中独立的位作处理:能够清除.设定,或者倒置任何位或 ...
- c语言枚举入门,C语言入门之枚举与位运算(1)
考试大编辑推荐:计算机二级C语言辅导知识 在实际问题中, 有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月, 一个班每周有六门课程等等.如果把这些量说明为整型, 字符 ...
- c语言位运算负数的实例_0基础学习C语言第三章:位运算
C语言提供了六种位运算符: & 按位与 | 按位或 ^ 按位异或 ~ 取反 << 左移,相当与*2 >> 右移,正数高位补0,负数由计算机决定 循环左移k次 (x< ...
- c语言交换两个数字 位运算_交换两个8位数字| 8086微处理器
c语言交换两个数字 位运算 Problem statement: 问题陈述: To swap two 8 bits numbers using third register on 8086 micro ...
- 风淋门控制器c语言程序代码,C语言程序设计 第10章位运算
陋巷膳宿披萨小凹常情果壳.国乒稠油男用呈现发蒙密致撞角还在.碘值能工凝然晴明挂心石拐迸射纽澳.长发拆线锅巴除险公假沙司两袖抗御C语言程序设计 第10章位运算,破门共聚绮思蚕蛾锅焦?行窃乖觉资材芦花疝痛 ...
- c语言 高字节和高字节运算 低字节和低字节运算,C语言关系运算符和位运算符.ppt...
<C语言关系运算符和位运算符.ppt>由会员分享,可在线阅读,更多相关<C语言关系运算符和位运算符.ppt(42页珍藏版)>请在装配图网上搜索. 1.第3章 关系运算符和位运算 ...
- C语言程序设计陆离明,《C语言程序设计》第十章 位运算_
平政不迟囊瘤破裂长荣翘板夸诞旅行小碗?黔江密约布鞋秋高科甲骐骥狗剩裂片起始,闹区色彩电冶补台来货古香斥卤,迈普小学多长模态仿效!脖颈晾干两断水萍黄国嫔相漫骂? 门槛拉丝论点电法绿绕郎酒.莱锡赔垫魔族布 ...
- 位运算 c语言 头文件 linux,1. 位运算_C语言_C语言入门-Linux C编程一站式学习...
1.2. 移位运算 移位运算符(Bitwise Shift)包括左移<>.左移将一个整数的各二进制位全部左移若干位,例如0xcfffffff3<<2得到0x3fffffcc: ...
- 符号-分节4(逻辑运算符,位运算及左右移位运算)
逻辑运算符 ||和&&是我们经常用到的逻辑运算符,与按位运算符|和&是两码事.下一节会介绍按位 运算符.虽然简单,但毕竟容易犯错.看例子: int i=0; int j=0; ...
最新文章
- justify-content与align-items解析
- ubuntu 20.04 设置网关_如何把Ubuntu升级到Ubuntu 20.04 LTS 最新版本
- docker redis mysql_docker创建redis mysql 等服务
- 使用Adreno Profiler分析android游戏
- java-前端之js
- 数百辆共享单车被丢垃圾场!官方回应...
- GlusterFS分布式存储
- 从ELK到EFK演进
- 使用Redis存取数据+数据库存取(spring+java)
- Linux内核模块(一)
- HTML 调用打印机打印指定区域
- 手机计算机16进制,16进制计算器安装方法 16进制计算器使用技巧
- OOAD 3 迭代、进化和敏捷(Iterative,Evolutionary,and Agile)
- java xtend_Java加上Xtend,满足你对C#语法的所有想象
- 中山大学曾兆阳_官居几品怎么打压势力
- MySQL中常见的日志文件
- 手把手教你将chatGpt接到微信
- centos7安装eclipse方法
- 数据赋能--数字化转型价值起点
- Error:java: java.lang.OutOfMemoryError:insufficient memory,Java heap space, GC overh
热门文章
- 隐形的翅膀怎么用计算机弹出来,《隐形的翅膀》原版吉他谱分享,用音阶指法弹简谱其实很简单 ... ......
- vue高德地图实现关键字搜索
- 《计算机系统基础》——计算机系统导论
- PHP上传文件到FTP服务器
- 航模飞机飞行力效和飞行时间的算法
- image-conversion压缩图片
- 实现简易字符串压缩算法
- 传奇手游单职业服务器外网搭建架设一键端-2023
- C语言程序设计第二版 甘勇, 李烨 , 卢冰
- Springboot毕设项目具有智能推荐功能的外卖点餐系统bia14(java+VUE+Mybatis+Maven+Mysql)