增量构造法
构建集合,一次选出一个元素放入集合(可重集同样适用)
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100],b[100];
void subset(int cnt,int k){
for(int i=1;i<cnt;i++)
cout<<b[i]<<" ";//无论数组中有几个元素都要打印出来
cout<<endl;
for(int i=k;i<=n;i++){
if(i==1||a[i]!=a[i-1]){
b[cnt]=a[i];//每次从数组中选出一个元素
subset(cnt+1,i+1);
//为了防止集合重复,定序,i每次递归都要往前一步
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);//一定要排序
subset(1,1);
}
位向量法(不适合可重集,效率较低)
用一个bool数组判断此数是否选过
#include<bits/stdc++.h>
using namespace std;
int a[100];
bool b[100];
void subset(int cnt,int n){
if(cnt==n+1){
for(int i=1;i<=n;i++){
if(b[a[i]])
cout<<a[i]<<" ";
}
cout<<endl;
return ;
}
b[a[cnt]]=1;//选此数
subset(cnt+1,n);
b[a[cnt]]=0;
subset(cnt+1,n);//不选此数
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
subset(1,n);
}
二进制法(只用于1~n,最快)
n个数有2^n个子集,去掉空集,每个子集正好对应一个二进制
用二进制的0,1 表示对应的值是否存在
n个数都存在,为11111111(假设n为8),化成十进制则为2^n -1
这里我们把每一个二进制编码看做是子集,而不再看做二进制
原理是这样的,假设现在有 一个二进制1011,代表此子集中有0,1,3 ,现在只需取出这几个数
用1011 '&' 后面的二进制(2^i)
0001
0010
0100
1000
&作用后结果为
0001
0010
0000
1000
只要两个集合&后结果不为0,则 i 存在子集中,输出即可
#include<bits/stdc++.h>
using namespace std;
int n;
void subset(int k){
for(int i=0;i<n;i++){//将子集中的数取出来
if(k&(1<<i))
cout<<i+1<<" ";
}
cout<<endl;
}
int main(){
cin>>n;
for(int i=0;i<(1<<n);i++){//枚举所有的子集
subset(i);
}
return 0;
}