子集的生成—二进制枚举

Posted wizarderror

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了子集的生成—二进制枚举相关的知识,希望对你有一定的参考价值。

有这样的一个问题:

给定一个集合,让你输出所有的子集。

这时候二进制就派上了用场~

我们用0,1来表示当前位是否被保留,值为1则保留,为0则舍弃 ,如下图所示:

技术图片

那么对于一个有n个数的集合来讲,每一位有取和不取两种状态,一共就有2n种状态,我们可以从0一直枚举到2n来表示所有子集的状态。

但是现在问题又来了,对与我们枚举的数,你怎么知道哪一位是0,哪一位是1?

这个时候就要用到位运算的知识了,对于一个数S(子集的状态)我们拿它和0~n每一位i进行S&(1<<i)这样的运算就能得到对于的位是否为1(&运算符的特点是只有当对应位都为1时,运算结果才为1)

举个栗子,S = 13,对于的二进制码为1101

1101 & 0001得到第一位为1

1101 & 0010得到第二位为0

1101 & 0010得到第三位为1

1101 & 1000得到第四位为1

这样就得到我们取集合中的1,3,4位

实现代码:

for(int i = 0; i < (1<<n); i++) //二进制枚举每一个状态
    for(int j = 0; j < n; j++) //枚举该状态下二进制的每一位数值
        if(i&(1<<j)) //当前位是否为1
            printf("%d ", a[j]);

 

以上是关于子集的生成—二进制枚举的主要内容,如果未能解决你的问题,请参考以下文章

枚举子集&高位前缀和

二进制集合枚举子集

子集枚举的二进制算法

二进制枚举子集技巧

做实验 解题报告(二进制枚举子集)

UVA1354-Mobile Computing(二进制枚举子集)