【总结】二进制枚举子集

集合

所谓集合,是指由一个或多个确定的元素所构成的整体。

我们一般用大括号及其中的若干元素表示个集合,例如{1,3, 5}示包含元素 1 3 5 1、3、5 的一个集合,{a, x, abc}表示包含三个字符串元素的集合。

在集合中的元素没有先后顺序,例如,集合{1,2, 3}和集合{3, 1,2}等价的。

在集合中,有一些集合间的关系,我们这里会用到的一个关系是子集。我们说集合A是集合B的子集,表示A中的所有元素都在B中出现。

例如,对于集合{1,2,3,4,5}, {1,3,5}、 {2,5}、{4}都是它的子集,而{1, 4, 6}不是它的子集。
当集合中不包含任何元素时,我们称它为空集

二进制枚举子集

对于集合 A A ,可以用一个二进制数来表示集合A的某个子集 B B 。我们用二进制数的每一位表示集合 A A 中每个元素是否在子集B中出现,1表示出现,0表示未出现。

对于集合{ 0 , 1 , 2 , 3 , 4 , 5 , 6 0,1,2,3,4,5,6 }。那么二进制 ( 0101101 ) 2 (0101101)_2 就代表子集{ 0 , 2 , 3 , 5 0,2,3,5 };

二进制数位 6 5 4 3 2 1 0
二进制数值 0 1 0 1 1 0 1
选取的元素 \ 5 \ 3 2 \ 0

值得注意的是,我们的二进制数位通常倒着来看,这样是为了方便程序的编写,但这也会成为一个理解的难点

当然,我们还有各种各样的方式来表示一个集合的子集,但由于计算机内部位运算的便捷性,我们通常借助二进制和位运算完成集合的表示和运算。

例题

[得到整数 X X ]
对于n个互不相同的正整数,要从这n个正整数之中无重复地选取任意个数,使得选出的数的总和为X。现在你需要求出一共有多少种不同的选取方案。

对于这道题,我们就可以先枚举这n个数组成的集合的子集,把所有可能的二进制数依次枚举,然后根据枚举出的二进制找出对应的子集,从而求出该子集中所有元素的和.

完整代码:

#include <iostream>
using namespace std;

int main() {
    int n, x, ans = 0, a[30];
    cin >> n >> x;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
 	for(int i = 0; i < (1 << n); i++) {
        int num = 0;
        for(int j = 0; j < n; j++){
            if(i & (1 << j)) {
                num += a[j];
            }
        } 
        if(num == x) {
            ans++;
        }
    } 
    cout<<ans<<endl;
    return 0;
}

注意其中

i & (1 << j)

这是二进制枚举子集中的常用方法,其作用是得到二进制数 i i 的第 j j

猜你喜欢

转载自blog.csdn.net/tanfuwen_/article/details/106886603