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

子集生成

子集生成算法:给定一个一级和,枚举它的所有可能的子集。
输入:
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值