二进制枚举--最通俗易懂的讲解

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

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

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

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

                         4                       8                     2               6                7
二进制                        1                        0                     1               1                0
木棍的状态                       选                     不选                    选              选              不选
上面说有5个木棍如果全选的话就是11111对应的十进制数就是31,也就是(2^n)-1个集合,我们用(1 << n)- 1表示,区间【1,2^n-1】这个区间上每一个整数代表一个集合,上表就是数字为22(二进制:10110)所代表的集合:4、2、6。

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

for(int i = 0; i < (1 << n); i++)
设s = 13(二进制为1101)代表我们选0 2 3位置上的数值;

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

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

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

1<<0=1(1);

1<<1=2(10);

1<<2=4(100);

1<<3=8(1000);

1<<4=16(10000);

...

1<<7=128(10000000);

...

看出来了吧!我们只需要将13&(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
using namespace std;
int main()
{
    int n;
    cin >> n;
    for(int i = 0; i < (1<     {
        for(int j = 0; j < n; j++) //遍历二进制的每一位
        {
            if(i & (1 << j))//判断二进制第j位是否存在
            {
                printf("%d ",j);//如果存在输出第j个元素
            }
        }
        printf("\n");
    }
    return 0;
}
--------------------- 
作者:sugarbliss 
来源:CSDN 
原文:https://blog.csdn.net/sugarbliss/article/details/81099340 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(二进制枚举--最通俗易懂的讲解)