位运算符
按位与运算符(&)
参加运算的两个数据,按二进制进行与运算
运算的规则为: 0&0=0 0&1=0 1&0=0 1&1=1 (即两位同时为1,结果才为1,否则为0)
比如 3&5 即0000 0011&0000 0101=0000 0001 因此3&5的值为1
左移运算符 (<<)
a<<b 表示把a转为二进制后左移b位(在后面填b个0)例如100的二进制为1100100,而110010000转成十进制是400,那么100<<2=400 实际上a<<b的值实际上就是a乘以2的b次方,因为在二进制数后添加一个0就相当于该数乘以2
通常认为a<<1比a*2更快,因为前者是更底层的操作,因此程序中乘以2的操作尽量用左移一位表示
二进制枚举
算法原理
二进制数据用0和1表示的数
二进制枚举利用每一位上的1或0数字表示选或者不选该位置上的对应元素,实现2的n次幂种情况下的枚举问题
从所有是0的情况考虑到所有是1的情况
1111111 2的7次幂
两层循环 一层循环是你整个枚举的范围,第二个循环是你没种情况下是否满足循环条件
枚举范围
for(a=0;a<(1<<n);a++);
怎样知道一个数据a的二进制位某一位i是以1还是0呢?如何来进行判断
for(i=0;i<n;i++)//逐个位去判断
if(a & 1<<i)//i=0的时候和1做&,i=1的时候和10做与
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a,i;
cin>>n;
for(a=0;a<(1<<n);a++)//从0到2的n-1次幂个状态
{
for(i=0;i<n;i++)//遍历二进制的每一位
{
if(a&(1<<i))//判断二进制i位是什么
printf("%d ",i);//如果存在的话输出第i个元素
}
printf("\n");
}
return 0;
}
要知道是如何实现的
1.比如有5个数,没选上用0表示,选上用1表示 就是从00000到11111 也就是[0,2^n-1]
可以用1的左移来表示,因为每左移一次就是给原数字乘2
2.然后我们要遍历每一位,看这个位置上是0还是1,有一个特别好的方法就是利用位运算并和1进行&运算,位运算可以让1的位置向左移,其余位置补0,然后利用按位与则可以得到当前位置是不是1,因为与的规则是当两个数都为1时,结果才为1.
二进制枚举的典型例题
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i,a,js,s[53],sum,n,k;
while(scanf("%d%d",&n,&k)&&n)
{
sum=0;
for(i=0;i<n;i++)
scanf("%d",&s[i]);
for(a=0;a<1<<n;a++)
{
js=0;
for(i=0;i<n;i++)
{
if(a&1<<i)
js++;
}
if(js==k)
{
for(i=0;i<n;i++)
{
if(a&1<<i)
printf("%d",s[i]);
}
printf("\n");
sum++;
}
}
printf("%d\n",sum);
}
return 0;
}