暴力求解法_子集生成(增量构造法,位向量法,二进制法)

子集生成

子集生成算法:给定一个一级和,枚举它的所有可能的子集。

输入:

4

输出:

增量构造法

第一种思路是一次选出一个元素放到集合中

code:

#include 
int A[1010];
void print_subset(int n,int* A,int cur){
    int flag=0;
    for(int i=0;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;i1;
    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 
int B[1001];
void print_subset(int n,int *B,int cur){
    if(cur==n){
        for(int i=0;iif(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=1,即1*2;
- n=2,即1*2*2;
- n=4,即1*2*2*2*2;转化为二进制10000.

code:

#include 
void print_subset(int n,int s){
    int flag=0;
    for(int i=0;iif(s&(1<printf("%d ",i+1);flag=1;}
    if(flag==1) printf("\n");
}
int main() {
    int i,n;
    scanf("%d",&n);
    for(i=0;i<(1<//枚举各子集所对应的编码0,1,2...,2^n-1
        print_subset(n,i);
    }
    return 0;
}

你可能感兴趣的:(算法竞赛入门,暴力求解法)