您的位置:首页 > 编程语言 > C语言/C++

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

2017-08-07 16:04 387 查看

子集生成

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

输入:

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 41 2 41 3
1 3 41 42
2 3
2 3 42 43
3 44


位向量法

第二种思路是构造一个位向量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 41 2 3
1 2 41 2
1 3 41 3
1 41
2 3 42 3
2 42
3 43
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息