我们定义该问题如下:
给定一个集合C,找出所有的集合C',使得C'包含于C。
一、无重复元素的集合
我们首先来考虑一种简单的情形,C中的数都是各不相同的,这就意味着所产生的子集不会有重复的。
直观来说,求一个集合的子集,无非就是对每个元素进行枚举,枚举两种状态”选“还是”不选“。例如,对一个集合C,当对cur这个位置的元素进行枚举时,对剩余的元素可以递归调用这个枚举的过程,当cur为数组长度n时,代表枚举结束。
子集的解空间又叫子集树,其叶子节点所代表的状态即为所有的子集。例如,集合{1,3,5},其子集树如下所示:
如上图所示,共有8个叶子节点,代表8个子集,有了子集树,要求出所有的子集,显然就是一个二叉树的先序遍历问题了,这里我们要设置一个与原数组一样大的标志数组,来标志当前位置”选“还是”不选“,因此,这种方法又叫”位向量法“,代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int n; 5 int A[20]; 6 int B[20]; 7 8 void print_subset(int n, int* B, int cur) 9 { 10 if(cur == n) 11 { 12 for(int i = 0; i < cur; i++) 13 if(B[i]) printf("%d ", A[i]); // 打印当前集合 14 printf("\n"); 15 return; 16 } 17 B[cur] = 1; // 选第 cur 个元素 18 print_subset(n, B, cur+1); 19 B[cur] = 0; // 不选第 cur 个元素 20 print_subset(n, B, cur+1); 21 } 22 23 int main() 24 { 25 scanf("%d",&n); 26 for(int i=0; i<n; i++) 27 scanf("%d",&A[i]); 28 29 print_subset(n,B,0); 30 system("Pause"); 31 32 return 0; 33 }