子集生成
子集生成算法:给定一个一级和,枚举它的所有可能的子集。
输入:
4
输出:
增量构造法
第一种思路是一次选出一个元素放到集合中
code:
#include <stdio.h>
int A[1010];
void print_subset(int n,int* A,int cur){
int flag=0;
for(int i=0;i<cur;i++)//打印当前集合
{printf("%d ",A[i]);flag=1;}
if(flag==1) printf("\n");
int s= cur ? A[cur-1]+1:1;//确定当前元素的最小可能值
for(int i=s;i<=n;i++){
A[cur]=i;
print_subset(n,A,cur+1);
}
}
int main() {
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)A[i]=i+1;
print_subset(n,A,0);
return 0;
}
输入:
4
输出:
1
1 2
1 2 3
1 2 3 4
1 2 4
1 3
1 3 4
1 4
2
2 3
2 3 4
2 4
3
3 4
4
位向量法
第二种思路是构造一个位向量B[i],而不是直接构造子集A本身,其中B[i]当且仅 i 在子集A中。
code:
#include <stdio.h>
int B[1001];
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+1);
//打印当前集合,注意此时B[i]保存的是子集A是否已经使用的状态
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;
}
输入:
4
输出:
1 2 3 4
1 2 3
1 2 4
1 2
1 3 4
1 3
1 4
1
2 3 4
2 3
2 4
2
3 4
3
4
二进制法
另外,还可以使用二进制来镖师{0,1,2…,n-1}的子集S:从右往左第 i 为(各位从0开始编号)表示元素i是否在集合S中。
1先转成二进制 在左移n位 然后补0
比如 1<<2 ,1的二进制为 0000 0001,左移2位 0000 0100。 如果再转成10进制就是4。
例如:
for(i=0;i<(1<<n);i++)
- n=1,即1*2;
- n=2,即1*2*2;
- n=4,即1*2*2*2*2;转化为二进制10000.
code:
#include <stdio.h>
void print_subset(int n,int s){
int flag=0;
for(int i=0;i<n;i++)
if(s&(1<<i))
{printf("%d ",i+1);flag=1;}
if(flag==1) printf("\n");
}
int main() {
int i,n;
scanf("%d",&n);
for(i=0;i<(1<<n);i++){//枚举各子集所对应的编码0,1,2...,2^n-1
print_subset(n,i);
}
return 0;
}