C/C++ 子集生成算法整理
个人笔记,仅供复习
1.概念:给定一个集合,枚举所有可能的子集。
2.常用算法
- 增量构造法
- 位向量法
- 二进制法
3.增量构造法
3.1 思路:一次选出一个元素放到集合中。
3.2 代码实例:
void print_subset(int n,int *A,int cur){
	for(int i = 0;i < cur;i++)	cout << A[i] << " ";//打印当前子集 
	cout << endl;
	int s = cur ? A[cur-1]+1:0;
	for(int i = s;i < n;i++){
		A[cur] = i;
		print_subset(n,A,cur+1);
	}
}3.3代码解析:
- 其中cur指的是当前元素的位置。上述代码的作用是读入n,输出{0,1,2,3,…,n-1}的所有子集。第五行中的 s 指的是 当前还可以放入集合A中的最小元素。
- 上述代码用到了定序的技巧。所谓的定序就是规定集合A中的所有元素按照从小到大排列,这样就不会出现{1,2}和{2,1}这样重复的集合了。
- 上述代码的作用是输出{0,1,2,3,…,n-1}的所有子集。如果要输出自定义集合的子集,只需要将A[i]当作下标,这样就可以输出自定义的集合了。
4.位向量法
4.1 思路:构造一个位向量B[i],而不是直接构造集合本身,其中B[i] = 1,当且仅当i在子集A中。
4.2 代码实例:
void print_subset(int n,int *B,int cur){
	if(cur == n){
		for(int i = 0;i < cur;i++)
			if(B[i])	cout << i << " ";
		cout << endl;
		return;
	}
	B[cur] = 1;
	print_subset(n,B,cur+1);
	B[cur] = 0;
	print_subset(n,B,cur+1);
}5.二进制法
5.1 思路:可以用二进制表示子集,其中从右往左第i位(从0开始编号)表示元素i是否在集合中(1表示在,0表示不在)。
5.2 代码实例:
#include<iostream>
using namespace std;
void print_subset(int n,int s){
	for(int i = 0;i < n;i++)
		if(s&(1<<i))	cout << i << " ";
	cout << endl;
}
int main()
{
	int n;
	cin >> n;
	for(int i = 0;i < (1<<n);i++)
		print_subset(n,i);//枚举各子集对应的编码0,1,2,…,2^n-1.
	return 0;
}5.3 代码解析:
- 首先要明白位移运算符(<<)的作用;第五行对1使用位移运算符,(1<<i)指的是将1向左移动i位,右面补0。
- 若一个集合中有n个元素,那么它的子集有2^n个,而假设每个元素只有存在(1)和不存在(0)两种状态,那么它的子集可以看成不同的二进制串,即每个子集可以代表且仅代表一个不同的十进制数,共2^n个不同的十进制数,这也就说明了每个十进制数代表了一个不同的二进制串,即每个十进制数代表了一个子集,因此可以有上述代码第13行写法。具体关系如下:
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号