方法一:增量構造法數組
理解遞歸必須得理解函數究竟是作什麼的。函數
#include<cstdio> void print_subset(int n,int *a,int cur) //print_subset的功能是打印集合{0,1,...,n-1}的cur個元素的子集,而且目前a數組中已經存儲了要打印的集合 { printf("{ "); for (int i=0;i<cur;i++) printf("%d ",a[i]); printf("}\n"); int mi=cur?a[cur-1]+1:0; //利用字典序避免重複打印 for (int i=mi;i<n;i++) //枚舉下一位能夠添加什麼元素 { a[cur]=i; print_subset(n,a,cur+1); //遞歸打印cur+1個元素的子集 } } int main() { int n; int a[10]={}; scanf("%d",&n); print_subset(n,a,0); //初始時a中存儲了0個元素的子集,開始遞歸打印 return 0; }
方法二:位向量法spa
枚舉每一位選或者不選,複雜度比方法一略高但更好理解,由於與輸出全排列思路差很少,滿n位就輸出。code
#include<cstdio> int a[10]; void print_subset(int n,int *b,int cur) //肯定第cur位選或者不選 { if (cur==n) //若是肯定好了n位,打印結果 { printf("{ "); for (int i=0;i<n;i++) if (b[i]) printf("%d ",a[i]); printf("}\n"); } else { b[cur]=1; //這一位選 print_subset(n,b,cur+1); //遞歸下一位 b[cur]=0; //這一位不選 print_subset(n,b,cur+1); //遞歸下一位 } } int main() { int n; int b[10]={}; scanf("%d",&n); for (int i=0;i<n;i++) a[i]=i; print_subset(n,b,0); return 0; }
缺點是輸出不是按照字典序。blog
方法三:二進制法遞歸
稍加思考就會發現,方法二其實與二進制是對應的。io
#include<cstdio> int a[10]; void print_subset(int n,int b) //n位的集合,b狀態打印 { printf("{ "); for (int i=0;i<n;i++) if (b&(1<<i)) printf("%d ",a[i]); printf("}\n"); } void p_s(int n) { for (int i=0;i<(1<<n);i++) print_subset(n,i); //枚舉全部狀態 } int main() { int n; scanf("%d",&n); for (int i=0;i<n;i++) a[i]=i; p_s(n); return 0; }
這個方法優勢就是代碼簡單。class
注意:以上三種方法輸出順序不一樣。二進制