子集生成的三种方法

子集生成的三种方法


最近遇到一个子集生成的题  没有很快的写出来  所以在把之前的过的子集生成方法在复习一边

第一种  增量构造法

在lrj紫书中  这是放到第一个讲解的 。。。。。。

顾名思义 增量构造法 就是按照递增顺序就行构造子集 防止子集的重复 如 集合{1,2} 就不会输出{1,2} 和{2,1}这样重复的子集了 在解答书中生成 2^n方个子集

直接看代码吧

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 300 
int A[100]; 
void print_subset(int n,int *A,int cur)
{
	for(int i=0;i<cur;i++)
		printf("%d ",A[i]);//输出子集 当前的集合 
	printf("\n");
	int s=cur?A[cur-1]+1:0;//确定当前最小的可能值  如果这里不是 这里特殊的就是cur==0时 其他的就是选比前一个大1的 
	for(int i=s;i<n;i++)
	{
		A[cur]=i;//将i加入当前的集合
		print_subset(n,A,cur+1);// 递归构造子集 
	 } 
}
int main()
{
	int n;scanf("%d",&n);
	print_subset(n,A,0); 
}
第二种 位向量法

这个就不多数了 最简单的 就i是选与不选 代码比较好些 容易理解 但是解答树节点是 2^n+1-1 比上面的大一倍

容易处理他给出的集合

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 300 
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); 
}

第三种 也是应用最广的一种 这种思想在很多地方都能用到 非常好用 二进制法

简单的说就是二进制的每一位代表一个数 

   A              B             A&B          A|B         A^B

10110      01100        00100       11110      11010

 {1,2,4}                {2,3}                       {2}                  {1,2,3,4}            {1,3,4}

可以看出分别对应 交 并 差 全集是 n个1 就是2^n-1  all_set=(1<<n)-1 则A的补集是all_set^A

 上代码吧

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 300 
int B[100]; 
void print_subset(int n,int s)
{
	for(int i=0;i<n;i++)
		if(s&(1<<i))printf("%d ",i);
	printf("%n");
}
int main()
{
	int n;scanf("%d",&n);
	for(int i=0;i<(1<<n);i++)
		print_subset(n,i); 
}
下面是一些集合的操作 

空集                            s=0

只含有第i个元素                                         1<<i

含有全部n个元素                                        (1<<n)-1

判断第i个元素是否属于集合S                        S>>i &1

向集合中加入第i个元素                                 s|=1<<i

从集合中去除元素i                                         s&~(1<<i)

集合S和集合T的并集                                      S|T
集合S和集合T的交集                                       S&T


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值