问题描述:
给定一个集合,比如{1,2,3,4},要生成所有的子集(不包括空集,也就是2^n-1个集合)
注: n个元素集合有2^n个子集.
1.增量构造法
思路:在已有子集的基础上不断增加新的元素,一直到无法继续添加为止. 另外因为我们排序的是数组的索引,是从小到大的,就不会出现重复的了.
参考代码
#include<iostream> #include<cstdio> using namespace std; int A[101];//存放集合元素下标的的数组 void print_subset(int n,int *A,int cur){//cur:当前A序列中元素的个数. for(int i = 0;i < cur;i++){//打印当前集合,每次进入都要进行打印 printf("%d",A[i]); } printf("\n"); int s = cur ? A[cur-1]+1:0; // 确定下一个元素的最小值 for(int i = s; i < n;i++){//从前往后进行枚举 第一次 A 一定包含A[s]元素, 第二轮则是一定包含A[s+1]元素 A序列中的元素一定都是从小到达的 A[cur] = i; print_subset(n,A,cur+1);//继续构造子集. } } int main() { int n; scanf("%d",&n); print_subset(n,A,0); return 0; }
运行结果:
2.位向量法
思路:使用一个数组来进行标记对应位置的元素是否存在,标记位置为0表示不存在,为1表示存在.
参考代码
#include<iostream> #include<cstdio> using namespace std; int B[10]; void print_subset(int n,int *B,int cur){ if(cur==n){ for(int i = 0; i < cur;i++){ if(B[i]){ printf("%d",i); } } printf("\n"); return; } B[cur] = 1;//选第cur个元素 print_subset(n,B,cur+1); B[cur] = 0;//不选第cur个元素 print_subset(n,B,cur+1); } int main() { int n; scanf("%d",&n); print_subset(n,B,0); return 0; }
运行结果
3.二进制法
有点复杂,自己目前还有点迷糊.
#include<cstdio> #include<iostream> using namespace std; void print_subset(int n,int s){ for(int i = 0;i < n;i++){ if(s&(1<<i)){ printf("%d",i); } } printf("\n"); } int main() { int n; scanf("%d",&n); for(int i = 0; i < (1<<n);i++){// print_subset(n,i); } return 0; }