问题描述:枚举给定集合的所有子集,包括只含一个元素的集合以及给定集合本身。当集合中出现值相同的元素时,根据不同性质可将子集分为:
- 允许重复包含相同值的元素
- 不允许重复包含相同值的元素
思路:利用二进制的“开关”特性枚举,具体为:假设给定集合A大小为n,则想象A = {a[0], a[1], ..., a[n-1]}的每个元素对应一个开关位(0或1),0表示不出现,1表示出现。当每个元素的开关位的值确定时,就得到一个子集,因此共有2^n-1种情况(全0为空集,这里不考虑)。我们利用区间[1, 2^n-1],该区间上的每一个整数对应一个子集,对应方法是遍历该整数二进制表示的每一位,若该位为1则相应子集中存在对应元素,否则不存在。
需要注意的是:对于上述第一种子集,二进制法可直接使用;而对于第二种子集,使用二进制法之前需要先对集合进行“去重”(可利用hash表去重)
代码:
void process(int a[], int n){
for(int i = 1; i < (1<<n); i++){ //1<<n相当于2^n,i表示区间中的某一个整数
for(int j = 0; j < n; j++){ //用j遍历区间中每一个整数的每一位
if((i>>j)&0x01 == 0x01) //该为为1,对应元素a[j]存在
printf("%d ", a[j]);
}
printf("\n");
}
}