C++位运算基本知识
与
input_1 | input_2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
// C++ a与b表示
a & b
或
input_1 | input_2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
// C++ a或b表示
a | b
非
input | output |
---|---|
0 | 1 |
1 | 0 |
// C++ a非表示
!a
异或
input_1 | input_2 | output |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
// C++ a异或b表示
a ^ b
通过异或可以实现很多功能,例如模拟加法计算,快速找寻配偶等等。
补码
补码的提出的初衷就是希望计算机在运算的时候只使用加法
正数的补码和原码相同
负数的补码是取反码(符号位不变)以后再加1
按位取反
input | output |
---|---|
00000001 | 11111110 |
10000001 | 01111110 |
// C++ a的按位取反
~a
通过按位取反,我们可以实现lowbit功能,即找寻某一数字,最低位的1。
//例如输入10010100,可以返回00000100,即最低位1表示的数字
int lowbit(int num){
return (~num + 1) & num;
}
左移、右移
左移n位相当于,原数乘上2的n次方
右移n位相当于,原数除以2的n次方
移位又分为算术移位和逻辑移位,C++和Python都是算数移位。
//C++ a左移n位
a << n;
//C++ a右移n位
a >> n;
位运算例题
快速幂
题目1:求a的b次方对p取模的值
首先我们会想到直接使用cmath头文件的pow函数可以很快求解。但pow函数在运算会返回double类型,如果输入数据过大就会溢出。
如果利用循环求解,每个循环中再求模,效率又太低。因此我们可以使用快速幂来加速我们的代码执行效率。
#include<iostream>
using namespace std;
int main(){
int a, b, p;
cin >> a >> b >> p;
int res = 1 % p;
while(b){
if (b&1) res = res * 1ll * a % p;
a = a * 1ll * a % p;
b >>= 1;
}
cout << res << endl;
return 0;
}
题目2:求a乘b对p取模的值
类比上题求解方式。
#include<iostream>
using namespace std;
typedef unsigned long long ULL
int main(){
ULL a, b, p;
cin >> a >> b >> p;
ULL res = 0;
while(b){
if (b&1) res = (res + a) % p;
a = a * 2 % p;
b >>= 1;
}
cout << res << endl;
return 0;
}
最短Hamilton路径
给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。
旅行商问题,是NP完全问题,目前还不能在多项式时间内求解,我们能做的就是优化暴力求解,本方法采用了状态压缩动态规划的方法加速计算。
我们定义一个状态用来表示哪些点我们已经到达,哪些点我们还没有访问到,用state来表示。
例如,state=001011,表示第0,1,3点已经访问。
我们设一个函数 f[state][j] ,表示当前走到 j 点的路径长度,我们的目标是求解 f[0111…1][n-1] ,并使其最短,采用动态规划可以表示成下式:
f[state][j] = min(f[state][j],f[state_j][k] + weight[k][j])
其中state_j代表着state将j点置0,代码如下。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20, M = 1 << 20;
int n;
int f[M][N], weight[M][N];
int main(){
cin >> n;
for (int i=0; i<n; ++i)
for (int j=0; j<n; j++)
cin >> weight[i][j];
memset(f, 0x3f, sizeof f);
f[1][0] = 0;
for(int i=0; i< 1<<n; ++i)
for(int j=0; j<n; ++j)
if(i >> j & 1)
for(int k=0; k<n; ++k)
if(i-(1 << j) >> k & 1)
f[i][j]=min(f[i][j], f[i-(1<<j)][k] + weight[k][j]);
cout << f[(1 << n) -1][n-1] << endl;
return 0;
}