子集生成问题

给你一个可比较大小顺序的集合,让你生成所有按照字典序排列的子集,本文借鉴自刘汝佳算法入门经典。

方法一:

增量构造法:一次选取一个元素到集合中。

#include <iostream>
using namespace std;
int a[20];
/*递归输出n以内所有的子集,其中cur为当前下标,初始值0*/
void print_subset(int n,int* a,int cur){
	for (int i=0;i<cur;i++)//每次递归输出当前子集,靠它来最后输出上一层指定的子集
		cout<<a[i]<<' ';
	cout<<endl;
	//找到当前子集首个值,因为按字典顺序输出,所以每次找到最小的元素,cur>0则minElem=a[cur-1]+1,否则为0
	int minElem = cur?a[cur-1]+1:0;

	for (i=minElem;i<n;i++)//设置每一层数的第一个值
	{
		a[cur]=i;

		//到达最后一层结束后自动回到上一层,然后i++,a[cur]的值(首元素)改变,又反复递归下一层...就像DFS树一样
		print_subset(n,a,cur+1);
	}
}

int main(){
	int n ;
	while (cin>>n){
		print_subset(n,a,0);
	}
	return 0;
}

注意:在枚举子集的增量法中已经进行定序,避免了同一集合出现两次。例如:0 1被列为0 1和1 0

方法二:

位向量法:通过构建位向量B[i],而不是直接构造子集A本身,当且仅当i在子集A中时,B[i]=1;

#include <iostream>
using namespace std;
bool b[20]={0};//判断当前每一个节点选中状态
/*递归输出n以内所有的子集,其中b表示该节点是否选中,cur为当前下标,初始值0*/
void print_subset(int n,bool* b,int cur){
	//当cur加到n的时候输出该串节点(解答树)的值
	if(cur==n){
		for (int i=0;i<n;i++){
			if(b[i])
				cout<<i<<' ';
		}
		cout<<endl;
		return ;
	}
	b[cur]=true;//该节点设为选中状态
	print_subset(n,b,cur+1);//cur+1递归该状态时的下一层节点,循环该操作
	b[cur]=false;//该节点设为不选中状态
	print_subset(n,b,cur+1);//cur+1递归该状态时的下一层节点,循环该操作
}

int main(){
	int n ;
	while (cin>>n,n){
		print_subset(n,b,0);
	}
	return 0;
}
时间: 2024-11-05 12:26:26

子集生成问题的相关文章

ACM:回溯法,子集生成

(一)增量构造法 #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1000; int A[MAXN], n; void print_subset(int n, int *A, int cur) { for(int i = 0; i < cur; ++i) cout << A[i] << " "; cout <<

uva11205 The broken pedometer 子集生成

PS:此题我在网上找了很久的题解,发现前面好多题解的都是没有指导意义的.后来终于找到了一篇好的题解. 好的题解的链接:http://blog.csdn.net/u013382399/article/details/23516051 我在他的解题的基础上,有了自己的理解. 题意: 有n(100以内)个位数为p(15以内)的二进制数,最少需要几个二进制位就可以把他们区分开. 题目分析: 数据较小,用的是暴力的方法,就是枚举每一个二进制位取或不取.就是相当于是枚举矩阵的列. 刘汝佳的小白书120页提到

子集生成模板、

1 //子集生成算法:给定一个集合,枚举所有可能的子集. 2 //为了简单起见,讨论的方法中没有重复元素 3 4 //增量构造法 5 #include<cstdio> 6 #include<cmath> 7 void print_subset(int n,int* A,int cur) 8 { 9 for(int i = 0 ; i < cur; ++i) printf("%d",A[i]); 10 printf("\n"); 11 i

Leetcode:Subsets 子集生成

Subsets: Given a set of distinct integers, S, return all possible subsets. Note: Elements in a subset must be in non-descending order. The solution set must not contain duplicate subsets. For example,If S = [1,2,3], a solution is: [ [3], [1], [2], [1

【模板】子集生成 二进制法

此文为博主原创,转载时请通知博主,并把原文链接放在正文醒目位置. 子集生成问题:给出一个正整数n,输入含有1~n共n个元素的集合的所有子集. 模板代码(qwq表示空集): 1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 6 inline void read(int &x) 7 { 8 char ch = getchar(),c = ch;

子集生成——暴力求解,枚举

子集生成:给定一个集合,枚举它所有可能的子集.(简单起见,这里假设集合中没有重复元素) 一.增量构造法 思路:一次选出一个元素放到集合中. Code: void print_subset1(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;//确定当前元素的最小可能值 for(in

POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成

昨天晚上12点刷到的这个题,一开始一位是BFS,但是一直没有思路.后来推了一下发现只需要依次枚举第一行的所有翻转状态然后再对每个情况的其它田地翻转进行暴力dfs就可以,但是由于二进制压缩学的不是很透,一直有小问题,下面我还会讲子集生成的相关方法,有兴趣的同学可以继续关注. 本题大意:一块地,有黑(1)白(0)之分,牛每次踩踏使得当前块以及四连块都变色,问当牛如何踩时使得地都变白并且求出最小踩踏次数和踩踏路径的最小字典序时的踩踏地图. 本题思路:由于同一块地被翻两次都会回到原来的状态,所以只需要对

uva 11205 The broken pedometer(暴力枚举+子集生成)

我终于可以说这是我自己独立完成的题目了,没看题解,没看注释,虽然用的时间成了写,总归有成就感的,昨天晚上就写了个大概,有点bug,由于太晚了,而且有点困了,就去睡了,当时真是自己认真想了的,,很深入的想了,用的书上刚学会的位向量自己生成来判断的.以后都要努力自己想,自己解决,专注...深入.... 思路: 就是先算出最少用m个灯才能表示n个数字,然后找第一个数字(由许多灯组成的0,1序列)的个数为m的子 集,把这n个子集作为n个数字的下标,判断一下有没有玩去一样的,如果有的话证明这两个数字不能通

【算法竞赛入门经典】7.3子集生成【增量构造法】【位向量法】【二进制法】

7.3.1增量构造法 思路:一次选出一个元素放到集合中.自己对于递归的理解还是不够,这里虽然没有明确给出递归停止条件,但是如果无法继续添加元素,就不会再继续递归,然后就是我头疼的回溯啦. #include<stdio.h> int num[4],n; void A(int n,int *a,int ans) { for(int i = 0; i < ans; i ++)//打印当前元素 printf("%d ",a[i]); printf("\n"