集合
所谓集合,是指由一个或多个确定的元素所构成的整体。
我们一般用大括号及其中的若干元素表示个集合,例如{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的某个子集 。我们用二进制数的每一位表示集合 中每个元素是否在子集B中出现,1表示出现,0表示未出现。
对于集合{ }。那么二进制 就代表子集{ };
二进制数位 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
二进制数值 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
选取的元素 | \ | 5 | \ | 3 | 2 | \ | 0 |
值得注意的是,我们的二进制数位通常倒着来看,这样是为了方便程序的编写,但这也会成为一个理解的难点
当然,我们还有各种各样的方式来表示一个集合的子集,但由于计算机内部位运算的便捷性,我们通常借助二进制和位运算完成集合的表示和运算。
例题
[得到整数
]
对于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)
这是二进制枚举子集中的常用方法,其作用是得到二进制数 的第 位