7.3子集生成

method 1 增量构造法
思路: 一次选出一个元素放到集合中
代码:

//A表示原集合 
//B表示子集和 
//N表示原集合个数 
//cur表示当前子集和个数 
#include<cstdio>
using namespace std;

void print_subset(int *A, int *B, int N, int cur){
	for(int i = 0; i < cur; i++)
		printf("%3d",B[i]);
	printf("\n");
	if(cur < N){
		for(int i = 0; i < N; i++){
			if(!cur || A[i] >B[cur-1]){
				B[cur] = A[i];
				print_subset(A, B, N, cur+1);
			} 
		}
	}
	
} 

int main(){
	int L = 3;
	int A[L] = {1, 2, 3};
	int B[L] = {0};
	print_subset(A, B, L, 0);
	printf("\n");
	return 0; 
}

method 2 位向量法
思路: 构造一个位向量B[i], 而不是直接构造子集A本身, 其中B[i] = 1 , 当且仅当 i 在子集 A 中
即 1个容量为N的集合,每个位置0~N-1,对于每个子集,要么被选中,要么没被选中。枚举每一个位置的状态,可得到各种子集。
递归实现

#include<cstdio>
using namespace std;
int B[100]; 
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);
		printf("\n");
		return ;
	}
	B[cur]=1;
	print_subset(n,B,cur+1);//选 
	B[cur]=0;
	print_subset(n,B,cur+1);//不选 
}
int main()
{
	int n;scanf("%d",&n);
	print_subset(n,B,0); 
}

method 3 二进制法
类似于位向量法,同样也是枚举各个位置的状态,但这次用二进制表示,二进制长度为N,与原集合大小相同。二进制的第 i 位代表原集合中的第 i 位是否被选中,枚举各种情况。集合大小为N,就是2的N次种方式。

/*算法思想 
	例如求4个元素 3 2 1 0 的子集。
	那么用二进制的1代表每一位是否选中。
十进制	二进制 
0	 	0000  代表空集
1	 	0001  代表{0}
2	 	0010  代表{1}
3	 	0011  代表{0,1}
4	 	0100  代表{2}
		 ...
15	 	1110  代表{3,2,1}
16	 	1111  代表{3,2,1,0} 
如果n很大的话可以用字符串模拟二进制 
*/
# include <stdio.h>
# include <algorithm>
using namespace std;
//二进制法求子集 
void print_subset(int n,int s){
	for(int i=0;i<n;i++){
		if(s & (1<<i)) //1左移i位,监测s的哪一位为1,为1的话输出 
			printf("%d ",i);
	} 
	printf("\n");
} 
int main() {
	int n=3;
	for(int i=0;i<(1<<n);i++){//1左移n位等价于2^n-1.因为子集个数2^n-1 
		print_subset(n,i);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值