我们定义该问题如下:

  给定一个集合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 }
View Code

相关文章: