我們定義該問題如下:
給定一個集合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 }
另一種有趣的構造子集的方法叫”增量構造法“,顧名思義,這種做法是一種增量式的做法,例如,對集合{1,3,5},首先確定第一個元素為1,這就是一個子集,然后再這個基礎上決定是不是增加3,或者5,形成另外兩個子集{1,3},{1,5},{1,3}再可以決定是不是要繼續增加5,而{1,5}中5已經到了最后,因此不能再添加,同樣,可以確定第一個元素為2,重復上述步驟。注意,這里集合是定序的,以防止重復。下圖給出了使用”增量構造法“對{1,3,5}進行子集搜索的子集樹。
下面我們給出使用”增量構造法“的子集生成代碼:

1 //增量構造法 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 int n; 7 int A[20]; 8 int B[20]; 9 10 void print_subset(int n, int* A, int cur); 11 12 int main() 13 { 14 scanf("%d",&n); 15 for(int i=0; i<n; i++) 16 scanf("%d",&A[i]); 17 18 print_subset(n,B,0); 19 system("Pause"); 20 21 return 0; 22 } 23 24 void print_subset(int n, int* B, int cur) 25 { 26 int i; 27 for(i= 0; i < cur; i++) printf("%d ",A[B[i]]); 28 printf("\n"); 29 int s = cur ? B[cur-1]+1 : 0;//確定當前元素的最小可能位置 30 for(i = s; i < n; i++) 31 { 32 B[cur] = i; 33 print_subset(n, B, cur+1);//遞歸構造子集 34 } 35 }
增量構造法可以很容易構造出指定大小的子集,只需要控制cur的大小指定輸出即可,比如要輸出長度不超過的3的子集,只要在程序一開始加上 if(cur>3) return; ,要輸出長度為3的,只需要在for循環外加一個if就行了。
練習題:
1、http://www.cnblogs.com/codershell/p/3619928.html
二、含有重復元素的集合
如果原數組中存在重復的元素,那么用上述方法在子集生成時就會產生重復的子集,這里我是采用最簡單的查重方法。代碼如下:

1 bool isExist(vector<vector<int> > &vv,vector<int> v){ 2 for(int i=0; i<vv.size(); i++) 3 if(vv[i] == v) 4 return true; 5 6 return false; 7 }
不知道有沒有什么巧妙的方法來解決這個問題。
練習題:
http://www.cnblogs.com/codershell/p/3621687.html