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

来源:互联网 发布:ubuntu mysqlsla 编辑:程序博客网 时间:2024/05/14 06:16

子集生成

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

输入:

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;}