二进制枚举

二进制:是计算技术中广泛采用的一种数制二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”

子集:是一个数学概念:如果集合A任意一个元素都是集合B的元素,那么集合A称为集合B子集

含有N个元素的集合的一切子集的个数为 2^n。简单证明一下:

  • 含有0个元素的子集有C(N,0)个,
  • 含有1个元素的子集有C(N,1)个,
  • 含有2个元素的子集有C(N,2)个,
  • .........
  • 含有N个元素的子集有C(N,N)

由二项式系数的性质可得:C(N,0)+C(N,1)+C(N,2)+...+C(N,N)=2^n

我们就是利用了二进制的特性 ,比如说有5个木棍的长度:4, 8, 2, 6, 7。我们就可以用01代表不选

如果选出长度为4、2、6的木棍,则如下表:

                     4                   8                 2           6            7
二进制                    1                    0                 1           1            0
木棍的状态                   选                 不选                选          选          不选

上面说有5个木棍如果全选的话就是11111对应的十进制数就是31,[0,2^{n}-1] 这个区间上每一个整数代表一个集合一共 2^n 个集合,上表就是数字22(二进制:10110)所代表的集合:4、2、6。

所以我们遍历每一个集合:

for(int i = 0; i < (1 << n); i++)

设s = 13(二进制为1101)代表我们选0 2 3位置上的数值;

那么我们如何找到每个位置上的数值呢?

我们遍历的是二进制的十进制表示(比如13),我们当然可以转化为二进制再枚举每一位,但是,这很麻烦;

一个很巧妙的方式就是利用位运算。

1<<0=1(0);

1<<1=2(10);

1<<2=4(100);

1<<3=8(1000);

1<<4=16(10000);

...

1<<7=128(10000000);

...

看出来了吧!我们只需要将13&(1<<i)我们便可以得到每一位是不是1 (1<< i 除了那一位,剩余的都是0,所以我们就可以得到那一位是不是1)

补充一波位运算的知识吧:

按位与运算符(&)

参加运算的两个数据,按二进制位进行“与”运算。

运算规则:0&0=0;  0&1=0;   1&0=0;    1&1=1;

      即:两位同时为“1”,结果才为“1”,否则为0

例如:3&5  即 0000 0011& 0000 0101 = 00000001  因此,3&5的值得1。

左移运算(<<)

 a << b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2(这样做要求保证高位的1不被移出)。
通常认为a << 1比a * 2更快,因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。

因此,我们便有了:

for(int j = 0; j < n; j++)
        if(i & (1 << j))
            printf(" %d ",a[j]);

那么完整的代码就是: 

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < (1<<n); i++) //从0~2^n-1个状态
    {
        for(int j = 0; j < n; j++) //遍历二进制的每一位
        {
            if(i & (1 << j))//判断二进制第j位是否存在
            {
                printf("%d ",j);//如果存在输出第j个元素
            }
        }
        printf("\n");
    }
    return 0;
}

例题1:ALGO-115_蓝桥杯_算法训练_和为T点击这里

例题2:HDU5616--Jam's balance点击这里

参考:

https://www.cnblogs.com/SunQi-lvbu/p/7305779.html

https://blog.csdn.net/riba2534/article/details/79834558

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值