
算法小课堂(一)暴力枚举
暴力枚举是一种简单朴素的算法思想,也称为穷举算法。其基本思想是对问题的所有可能情况进行逐一尝试,并从中找到符合条件的解决方案。暴力枚举算法通常通过循环或递归实现,其时间复杂度与问题规模成指数级关系,因此对于较大规模的问题不适用,但对于一些小规模问题,暴力枚举算法往往是可行的。在实现上,暴力枚举算法通常采用循环或递归的方式来实现。循环实现通常是嵌套多层循环,逐个枚举每个可能的情况,并在内层循环中对每
、
目录
一、概念
1.1相关概念
暴力枚举是一种简单朴素的算法思想,也称为穷举算法。其基本思想是对问题的所有可能情况进行逐一尝试,并从中找到符合条件的解决方案。
暴力枚举算法通常通过循环或递归实现,其时间复杂度与问题规模成指数级关系,因此对于较大规模的问题不适用,但对于一些小规模问题,暴力枚举算法往往是可行的。
在实现上,暴力枚举算法通常采用循环或递归的方式来实现。循环实现通常是嵌套多层循环,逐个枚举每个可能的情况,并在内层循环中对每种情况进行检查;递归实现则是将问题分解为更小的子问题,逐层递归求解,直到找到符合条件的解。
1.2应用场景
排列组合问题:如求解从 n 个元素中选取 k 个元素的所有可能组合,可以使用暴力枚举算法逐个枚举所有组合。
搜索问题:如迷宫问题、八皇后问题等,可以使用暴力枚举算法枚举所有可能的状态,然后检查每个状态是否满足问题要求。
子序列问题:如求解一个序列的最长递增子序列、最长公共子序列等,可以使用暴力枚举算法枚举所有子序列,并检查每个子序列是否满足要求。
数值计算问题:如求解多项式函数的值、求解复合函数的值等,可以使用暴力枚举算法枚举函数的参数,并计算函数的值。
基础算法问题:如素数判断、最大公约数、最小公倍数等,可以使用暴力枚举算法逐个枚举可能的解,然后检查是否满足问题要求。
1.3局限性
简单的枚举一般只适用于解决简单的问题
难以求出或范围特别大,明显超时(数论等)
二、相关问题
2.1例题1:统计
高数考试结果已经出来了,如果不及格就惨了,如果不及格,那开学还得补考,那这个春节就郁闷了!现在老师想知道有几名同学高数考试没及格,假设1个班级有N名同学! Input:输入数据有多组,每组1行,第1个数是N,(1<=N<=1000)接下来有N个数,这N个数都是0到100之间的整数。 Output:请输出每组的N个数中有多少个是小于60的?记得输出结果后要换行啊!
Sample Input 10 1 2 3 4 5 6 7 8 9 99
8 80 70 60 90 100 75 65 55
Sample Output 9
1
#include <stdio.h>
int main() {
int n;
while (~scanf("%d", &n)) {
int cnt = 0;
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
if (x < 60) cnt++;
}
printf("%d\n", cnt);
}
return 0;
}
优化
#include <stdio.h>
inline int read() { // 快读
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
inline void write(int x) { // 快写
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int main() {
int i, n;
while (~scanf("%d", &n)) {
int cnt = 0;
for (i = 0; i < n; i++) {
int x = read();
if (x < 60) cnt++;
}
write(cnt); putchar('\n');
}
return 0;
}
1.快读
快读是一种优化输入效率的技巧,它通过尽可能地减少读取输入流的次数来提高输入效率。在 C/C++ 中,通常使用 scanf 或者 getchar 来读入数据,但是这些函数的效率相对较低。因此,我们可以使用快读来替代这些函数,以提高输入效率。
快读的基本原理是:一次读入多个字符,然后通过位运算和加法等操作将这些字符转换为一个整数。快读通常会用到 getchar 函数来读入字符,因为 getchar 的效率比 scanf 更高。在读入数字的过程中,我们需要将读入的字符转换成数字。这个过程可以通过将读入的字符与 '0' 的 ASCII 码进行运算来实现。
2.快写
快写是一种优化输出效率的技巧,它通过尽可能地减少输出流的次数来提高输出效率。在 C/C++ 中,通常使用 printf 或者 putchar 来输出数据,但是这些函数的效率相对较低。因此,我们可以使用快写来替代这些函数,以提高输出效率。
快写的基本原理是:将一个整数拆分成若干个位数,然后将每个位数转换成字符并输出。在输出字符的过程中,我们需要使用 putchar 函数来输出字符。由于 putchar 的效率比 printf 更高,因此可以提高输出效率。
2.2例题二 二倍的问题
描述:给定2到15个不同的正整数,你的任务是计算这些数里面有多少个数对满足:数对中一个数是另一个数的两倍。比如给定1 4 3 2 9 7 18 22,得到的答案是3,因为2是1的两倍,4是2个两倍,18是9的两倍。
输入:输入包括n组测试数据。每组数据包括一行,给出2到15个两两不同且小于100的正整数。每一行最后一个数是0,表示这一行的结束后,这个数不属于那2到15个给定的正整数。 输出:对每组输入数据,输出一行,给出有多少个数对满足其中一个数是另一个数的两倍。
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
while (cin >> n&&n) {
vector<int> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] == 2 * nums[j] || nums[j] == 2 * nums[i]) {
cnt++;
}
}
}
cout << cnt << endl;
}
return 0;
}
优化
#include <iostream>
#include <vector>
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int main() {
int n;
while ((n = read()) != 0) {
vector<int> nums(n);
for (int i = 0; i < n; i++) {
nums[i] = read();
}
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] == 2 * nums[j] || nums[j] == 2 * nums[i]) {
cnt++;
}
}
}
write(cnt);
putchar('\n');
}
return 0;
}
2.3例题3 奶牛碑文
小伟暑假期间到大草原旅游,在一块石头上发现了一些有趣的碑文。碑文似乎是一个神秘古老的语言,只包括三个大写字母 C、O 和 W。尽管小伟看不懂,但是令他高兴的是,C、O、W的顺序形式构成了一句他最喜欢的奶牛单词“COW”。现在,他想知道有多少次 COW 出现在文本中。 如果 COW 内穿插了其他字符,只要 COW 字符出现在正确的顺序,小伟也不介意。甚至,他也不介意出现不同的 COW 共享一些字母。例如,CWOW 出现了 1 次 COW,CCOW 算出现了2 次 COW,CCOOWW 算出现了 8 次 COW。 输入:第 1 行为 1 个整数 N,第 2 行为 N 个字符的字符串,每个字符是一个 C、O 或 W。 输出:输出COW 作为输入字符串的子串出现的次数(不一定是连续的)。 提示:答案会很大,建议用 64 位整数(long long)。 Sample Input Sample Output
6 6 COOWWW
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
string s;
cin >> s;
long long cnt = 0;
int c = 0, co = 0, cow = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'C') {
c++;
} else if (s[i] == 'O') {
co += c;
} else if (s[i] == 'W') {
cow += co;
}
}
cout << cow << endl;
return 0;
}
我们可以通过遍历字符串,统计出在当前位置之前出现的'C'的个数,以及'C'和'O'组成'C'-'O'的个数,以及'C'-'O'-'W'的个数,也就是'COW'的个数。遍历时,如果当前字符是'C',就将'C'的计数器加1;如果当前字符是'O',就将'C'-'O'的计数器加上当前'C'的计数器,因为'O'只有在'C'的后面才能构成'C'-'O';如果当前字符是'W',就将'C'-'O'-'W'的计数器加上当前'C'-'O'的计数器,因为'W'只有在'C'-'O'的后面才能构成'COW'。
最后输出'COW'的计数器即可。
对于输入6CCOOWW,程序会执行以下操作:
- 读入整数6,表示接下来输入的字符串长度为6。
- 读入字符串CCOOWW。
- 定义三个计数器c、co、cow,初始值均为0。
- 进入for循环,i从0到5依次遍历字符串中的每一个字符。
- 当i=0时,s[i]='C',将c计数器加1,c=1。
- 当i=1时,s[i]='C',将c计数器加1,c=2。
- 当i=2时,s[i]='O',将co计数器加上c计数器,co=2。
- 当i=3时,s[i]='O',将co计数器加上c计数器,co=4。
- 当i=4时,s[i]='W',将cow计数器加上co计数器,cow=4。
- 当i=5时,s[i]='W',将cow计数器加上co计数器,cow=8。
- 完成循环,输出cow计数器的值8,表示字符串CCOOWW中共出现了8次COW。
2.4例四网友年龄
问题描述:
某君新认识一网友。当问及年龄时,他的网友说:“我的年龄是个2位数,我比儿子大27岁,如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦.
请填写表示可能情况的种数。
#include <iostream>
using namespace std;
int main() {
for (int i = 10; i <= 99; i++) {
int son = i - 27;
int reverse_i = (i % 10) * 10 + (i / 10);
if (son >= 0 && son <= 99 && son == reverse_i) {
cout << "网友的年龄是:" << i << endl;
}
}
return 0;
}
2.5例五生日年龄数
问题描述:
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。现在算起来,他一共吹熄了210根蜡烛。请问,他从多少岁开始过生日party的?
请输出他开始过生日party的年龄数。
注意:你输出的应该是一个整数,不要输出任何多余的内容或说明性文字。
输入
没有输入。
输出
输出一个整数,即某君开始过生日party的年龄数
#include <iostream>
using namespace std;
int main() {
int sum = 0; // 记录吹熄蜡烛的总数
int age = 0; // 记录从多少岁开始过生日party
while (sum < 210) { // 只要蜡烛总数还不足236根,就继续加上下一个年龄需要吹熄的蜡烛数
age++;
sum += age;
}
cout << age << endl; // 输出某君开始过生日party的年龄数
return 0;
}
2.6数学题例六
问题描述: 有限五位数 个位数为6且能被3整除的五位数有多少个?
#include <iostream>
using namespace std;
int main()
{
int count = 0; // 记录符合条件的五位数个数
for (int A = 1; A <= 9; A++)
{
for (int B = 0; B <= 9; B++)
{
for (int C = 0; C <= 9; C++)
{
for (int D = 0; D <= 9; D++)
{
int sum = A + B + C + D + 6; // 计算ABCDE6的各位数字之和
if (sum % 3 == 0) // 如果能被3整除
{
count++; // 计数器加1
long num = 10000*A+1000*B+100*C+10*D+6;
cout <<num<<endl;
}
}
}
}
}
cout << "个位数为6且能被3整除的五位数的个数为:" << count << endl;
return 0;
}
2.7林大OJ:丑数简单版
Description
只有质数2,3,5,7这几个作为因子的数叫做,丑数,比如前20个丑数是(从小到大来说) 1,2,3,4,5,6,7,8,9,10,12,14,15,16,18,20,21,24和25.Input
我们给你个n(1<= n<=2000)当输入n为0结束。Output
输出第n个丑数。每个数一行。Sample Input
1 2 3 4 11Sample Output
1 2 3 4 12
#include <iostream>
using namespace std;
// 判断一个数是否为丑数
bool isUgly(int n) {
while (n % 2 == 0) n /= 2; // 不断除以2
while (n % 3 == 0) n /= 3; // 不断除以3
while (n % 5 == 0) n /= 5; // 不断除以5
while (n % 7 == 0) n /= 7; // 不断除以7
return n == 1; // 如果最后等于1,说明是丑数,否则不是
}
int main() {
int n;
while(cin >> n && n){
int cnt = 0; // 已经找到的丑数的个数
int i = 1; // 当前枚举到的数
int num = 0; // 第n个丑数
while (cnt < n) { // 没找到第n个丑数之前不停循环
if (isUgly(i)) { // 如果当前数是丑数
cnt++; // 计数器加1
num = i; // 更新第n个丑数
}
i++; // 继续枚举下一个数
}
cout << num << endl; // 输出第n个丑数
}
return 0;
}
三、二进制枚举
3.1相关概念
二进制枚举是一种常用的算法技巧,它常用于对一个集合的所有子集进行枚举。在二进制枚举中,我们通常使用一个二进制数表示一个子集,二进制数中的每一位代表原集合中对应的元素是否被选中,1表示选中,0表示未选中。
3.2问题
3.2例题1:何以包邮?
题目描述 新学期伊始,适逢顿顿书城有购书满工元包邮的活动,小P同学欣然前往准备买些参考书。 -番浏览后,小P初步筛选出n本书加入购物车中,其中第i本(1≤i≤n)的价格为ai 元。 考虑到预算有限,在最终付款前小P决定再从购物车中删去几本书(也可以不删),使得剩余图书的价格总和m在满足包 邮条件(m≥x)的前提下最小。 试帮助小P计算,最终选购哪些书可以在凑够x元包邮的前提下花费最小? 输入格式 从标准输入读入数据。 输入的第- -行包含空格分隔的两个正整数n和r, 分别表示购物车中图书数量和包邮条件。 接下来输入n行,其中第i行(1≤i≤n)仅包含-个正整数ai, 表示购物车中第i 本书的价格。输入数据保证n本书的 价格总和不小于Eo 输出格式 输出到标准输出。 仅输出一个正整数,表示在满足包邮条件下的最小花费
对于n本书,可以用一个n位二进制数表示某本书是否要购买,即第i位二进制数为1表示购买第i本书,为0表示不购买。因此,可以枚举0到2^n-1的所有二进制数,对于每个二进制数,计算购买这些书的总价格,如果满足条件且总价格最小,则更新最小值。具体步骤如下:
- 读入购物车中图书数量和包邮条件,以及每本书的价格,并计算所有书的价格总和minsum。
- 二进制枚举0到2^n-1的所有二进制数,对于每个二进制数,计算购买这些书的总价格。
- 对于每个二进制数,可以通过位运算来提取各二进制位上的值,若第i位二进制数为1,则购买第i本书,累加其价格到总价格中。
- 如果购买这些书的总价格小于包邮条件x,则继续计算下一个二进制数。
- 如果购买这些书的总价格等于包邮条件x,则直接输出该价格并结束程序,因为此时已经得到最优解。
- 如果购买这些书的总价格大于包邮条件x且小于当前的最小总价格minsum,则更新最小总价格。
- 输出最小总价格。
#include <iostream>
using namespace std;
int main() {
int n, i, j, x, a[30], sum = 0, minsum = 0;
cin >> n >> x;
for (i = 0; i < n; i++) {
cin >> a[i];
minsum += a[i]; // 用各位和表示最大值.
}
for (i = 1; i < 1<<n; i++) {
sum = 0;
for (j = 0; j < n; j++) {
if (i & 1<<j) // 提取各二进制位上的值
sum += a[j]; // 位为1时,加上第i本书的价格
}
if (sum == x) {
minsum = x;
break;
} else if (sum > x && sum < minsum) {
minsum = sum;
}
}
cout << minsum << endl;
return 0;
}
核心代码说明
for (i = 1; i < 1<<n; i++) {
- i为购买书籍的组合方案,在1到2^n-1之间循环(二进制中的每一位都有取或不取两种可能)。
- 1<<n表示将1左移n位,相当于2的n次方,即总方案数。
- i从1开始循环是因为0表示不选任何书,而1表示选第一本书,以此类推。
- 循环结束条件是i达到2^n-1。
sum = 0;
- 初始化当前组合方案下的总花费为0。
for (j = 0; j < n; j++) {
- j为当前购物车中的书籍编号,从0到n-1依次枚举。
- 判断当前方案中是否选取了第j本书的方法是:将i和1左移j位进行按位与操作。
- 1左移j位相当于将1的二进制表示中的第j位变为1,其他位为0,即1<<j。
- i & 1<<j将1<<j这一位和i的对应位进行按位与操作,结果为0表示不选第j本书,结果不为0表示选第j本书。
if (sum == x) {
- 如果当前组合方案下的总花费恰好为包邮条件x,则直接将最小总花费设为x,结束循环。
} else if (sum > x && sum < minsum) {
- 如果当前组合方案下的总花费大于包邮条件x且小于之前的最小总花费,则更新最小总花费为当前组合方案下的总花费。
cout << minsum << endl;
- 输出最小总花费。
3.2例题2:诗仙李白的郁闷事
诗仙李白的郁闷事 大诗人李白,一生好饮。一天,他提着酒壶,从家里出来,酒壶中有酒两斗。他边走边唱: 无事街上走,提壶去打酒 逢店加一倍,遇花喝一斗。 这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,此时他正好把酒喝光了。请你计算李白遇到店和花的次序,并统计有多少种可能的方案。
#include <iostream>
using namespace std;
int main() {
int cnt = 0; // 统计方案数
for (int i = 0; i < (1 << 14); i++) { // 枚举所有14位二进制数
int shop_cnt = 0, wine_cnt = 2; // 分别表示店铺数量和酒量
string s = ""; // 用来存储每种情况的遍历结果
for (int j = 0; j < 14; j++) {
if (i & (1 << j)) { // 该位为1,遇到店铺
shop_cnt++;
wine_cnt *= 2;
s += '1';
} else { // 该位为0,遇到花
wine_cnt--;
s += '0';
}
if (wine_cnt == 1 && shop_cnt == 5 && j == 13) {
// 满足条件,方案数加1,并输出该种情况
cnt++;
cout << s << endl;
}
}
}
cout << "Total: " << cnt << endl;
return 0;
}
其中
(1 << 14)
表示 14 位二进制数的总数,即2^14
,使用二进制枚举的方法依次枚举所有的可能性。在循环体内,i & (1 << j)
表示提取i
的第j
位二进制数,如果为 1,则表示遇到了店铺,否则表示遇到了花,随后分别对酒量和店铺数量进行更新,如果满足条件则将方案数加 1。
3.2林大OJ:1205和为K--二进制枚举
Description
给出长度为n的数组,求能否从中选出若干个,使他们的和为K.如果可以,输出:Yes,否则输出NoInput
第一行:输入N,K,为数组的长度和需要判断的和(2<=N<=20,1<=K<=10^9) 第二行:N个值,表示数组中元素的值(1<=a[i]<=10^6)Output
输出Yes或NoSample Input
5 13 2 4 6 8 10Sample Output
No
#include <iostream>
using namespace std;
const int MAXN = 21;
int a[MAXN];
int main() {
int n, k;
while(cin >> n >> k){
for (int i = 0; i < n; i++) {
cin >> a[i];
}
bool found = false;
for (int i = 0; i < (1 << n); i++) { // 枚举所有子集
int sum = 0;
for (int j = 0; j < n; j++) {
if (i & (1 << j)) { // 如果第 j 个元素被选中
sum += a[j];
}
}
if (sum == k) {
found = true;
break;
}
}
if (found) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
3.2林大OJ:1505陈老师加油-二进制枚举
Description
陈老师经常开车在哈尔滨的大街上行走,假设刚开始油箱里有T升汽油,每看见加油站陈老师就要把汽油的总量翻倍(就是乘2);每看见十字路口气油就要减少1升;最后的时候陈老师的车开到一个十字路口,然后车就没油了------就熄火了,陈老师好痛苦啊~~~! 然后他就开始回忆,一路上一共遇到5个加油站,10个十字路口,问造成这种惨烈的境遇有多少种可能?Input
输入一个T ,(1<=T<=100);Output
输出可能的方案数。Sample Input
1Sample Output
10
#include <iostream>
using namespace std;
int main() {
int T;
while(cin >> T){
int cnt = 0;
for(int i = 0; i < (1 << 15); i++){
int cross = 0;
int gas = T;
int shop = 0;
bool flag = true;
for(int j = 0;j < 15;j++){
if(i & (1 << j)){
shop++;
gas *= 2;
}
else{
cross++;
gas--;
}
if(gas == 0)
break;
}
if (gas==0&& shop == 5 && cross == 10)
cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
3.2林大OJ:1665四糸乃买花-二进制枚举
Description
商店里有n朵花,四糸乃有w元钱。n朵花各不相同,四糸乃要买这n朵花其中的其中的若干朵。由于四糸乃很喜欢4这个数字,所以她希望她买的花的朵数是4的倍数,并且买完花后剩下的钱(可以为0)也是4的倍数。此外,因为已经来到花店了,所以四糸乃不能一朵花也不买。因为花店接下来还要做生意,四糸乃也不能将这n朵花全部买走。那么四糸乃一共有多少种买花方案呢?Input
单组输入 测试数据共三行。 第一行是一个整数n表示有n朵花。(2<=n<=22) 第二行有n个整数,分别表示这n朵花的价格a[i]。(1<=a[i]<=1e7) 第三行是一个整数w代表四糸乃开始时持有的钱数(1<=w<=1e8)Output
输出买花的方案数,输出占一行。Sample Input
5 5 6 1 3 4 39Sample Output
1Hint
只有一种方案,买第1,2,3,4朵花,买的朵数4是4的倍数且不为0不为n,剩余钱数24是4的倍数,符合题意。因为题目中只有这一种方案符合题意,所以答案是1
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, w;
cin >> n;
vector<int> flowers(n);
for (int i = 0; i < n; i++) {
cin >> flowers[i];
}
cin >> w;
int ans = 0;
// 枚举选花操作的状态
for (int s = 1; s < (1 << n); s++) {
int sum = 0; // 已选花的总价值
int count = 0; // 已选花的数量
for (int i = 0; i < n; i++) {
if (s & (1 << i)) {
sum += flowers[i];
count++;
}
}
if (count == n) {
break; // 不能将所有花都买走
}
if (sum > w) {
continue; // 不能超过总钱数
}
if (count % 4 == 0 && (w - sum) % 4 == 0) {
ans++; // 符合要求的方案数+1
}
}
cout << ans << endl;
return 0;
}
3.3位运算
位运算是一种针对二进制数字的运算,是计算机中常用的一种运算方式。位运算操作符主要包括按位与(&)、按位或(|)、按位异或(^)、按位取反(~)、左移(<<)和右移(>>)。
按位与(&)运算符:两个二进制数的每一位进行与运算,结果为1则为1,否则为0。 例如:1010 & 1100 = 1000
按位或(|)运算符:两个二进制数的每一位进行或运算,结果为0则为0,否则为1。 例如:1010 | 1100 = 1110
按位异或(^)运算符:两个二进制数的每一位进行异或运算,结果为相同则为0,不同则为1。 例如:1010 ^ 1100 = 0110
按位取反(~)运算符:对一个二进制数的每一位进行取反操作,0变为1,1变为0。 例如:~1010 = 0101
左移(<<)运算符:将一个二进制数的所有位向左移动n位,低位补0,相当于对该数进行乘2^n运算。 例如:1010 << 2 = 101000
右移(>>)运算符:将一个二进制数的所有位向右移动n位,高位补0或补1(取决于原数的符号位),相当于对该数进行除2^n运算。 例如:1010 >> 2 = 0010
特殊用法:
1.交换变量值
使用位运算可以快速交换两个变量的值,而无需使用中间变量。例如:
int a = 5, b = 10; a ^= b; b ^= a; a ^= b;
执行完以上代码后,a的值变成了10,b的值变成了5,实现了快速交换变量的值。
2.判断奇偶性
使用位运算可以快速判断一个数的奇偶性。具体来说,如果一个数的二进制表示的末位是0,则这个数是偶数,否则这个数是奇数。因此,可以使用按位与运算(&)来判断奇偶性,如下所示:
int x = 5; if (x & 1) { // x是奇数 } else { // x是偶数 }
3.最大值和最小值
使用位运算可以很快地求出两个整数的最大值和最小值,假设有两个整数 a 和 b,可以使用以下代码:
int max = b ^ ((a ^ b) & -(a < b)); // 求最大值 int min = a ^ ((a ^ b) & -(a < b)); // 求最小值
4.求平均数
double ave = (a & b) + ((a ^ b) >> 1); //求平均值
更多推荐
所有评论(0)