算法03:子集生成算法总结
2014-04-10 12:05
218 查看
给定一个正整数n,列出{1,2,3,...n}的子集,常用的方法有如下三种:
1.增量构造法
2.位向量法
3.二进制法
增量构造法
基本思想:每次取一个元素加入集合中,再向新集合中加入剩余的元素
如求{1,2,3}的子集,假设集合中的元素按从小到大排列
1.首先选一个元素,集合可以依次选A1={1},B1={2},C1={3}
2.A1中加入一个元素,集合可以为A2={1,2},A3={1,3},
3.A2中加入一个元素,集合可以为A4={1,2,3},而A3中已经不能再添加元素
4.同理,B1、C1中也可以依次添加元素
实际上是一个递归的过程,首选循环取出一个元素A,以A开始再循环一个个取出剩下的元素B,相当于以B开始再重复这一过程,求子集的函数如下
void print_sub1(int cur)
{
int i, j;
for(i = 0;i < cur; i++)
cout<<set[i]+1<<" ";
cout<<endl;
total++;
/*
j是每次递归集合中的最小值
*/
j = cur?set[cur-1]+1:0;
for(i = j; i < n; i++){
set[cur] = i;
print_sub1(cur+1);
}
}
位向量法
构造子集的另一种方法是,对集合中的每一个数,我们可以选择取出或者不取,这样我们可以构造一个位向量数组bit,其下标对应集合中元素的位置,bit中的值为1表示对应的数组元素在子集中,为0则不在其中,这样我们就可以用递归方法实现
void print_sub2(int cur)
{
if(cur == n){
for(int i = 0;i < n; i++)
if(!bit[i]) cout<<i+1<<" ";
cout<<endl;
total++;
return;
}
//每一个数有取或不取两种选择
bit[cur] = 1;
print_sub2(cur+1);
bit[cur] = 0;
print_sub2(cur+1);
}
二进制法
受前一种方法的启发,可以把子集表示为0和1组成的串,{1,2,3}构造子集的过程如下:
321 321 321
321 ...... 321
001 010 011 100 ...... 111
1 2 12 3 ...... 123
只要一个整型数逐一递增再与相应元素按位与就可以枚举出所有的子集,但是该方法有一个缺陷,就是集合的个数不能大于在计算机中一个整型数的位数,一般为32位,算法如下:void print_sub3()
{
int i,j;
//子集的个数为2^n, 1<<n相当于1*2^n
for(i = 0; i<(1<<n); i++){
for(j = 0; j < n; j++){
if(i&(1<<j)) cout<<j+1<<" ";
}
cout<<endl;
total++;
}
}
完整算法:
#include <cstdlib>
#include <iostream>
using namespace std;
int set[20], n, total, bit[20];
void print_sub1(int cur)
{
int i, j;
for(i = 0;i < cur; i++)
cout<<set[i]+1<<" ";
cout<<endl;
total++;
/*
j是每次递归集合中的最小值
*/
j = cur?set[cur-1]+1:0;
for(i = j; i < n; i++){
set[cur] = i;
print_sub1(cur+1);
}
}
void print_sub2(int cur)
{
if(cur == n){
for(int i = 0;i < n; i++)
if(!bit[i]) cout<<i+1<<" ";
cout<<endl;
total++;
return;
}
//每一个数有取或不取两种选择
bit[cur] = 1;
print_sub2(cur+1);
bit[cur] = 0;
print_sub2(cur+1);
}
void print_sub3()
{
int i,j;
//子集的个数为2^n, 1<<n相当于1*2^n
for(i = 0; i<(1<<n); i++){
for(j = 0; j < n; j++){
if(i&(1<<j)) cout<<j+1<<" ";
}
cout<<endl;
total++;
}
}
int main()
{
while(cin>>n){
total = 0;
//print_sub1(0);
//print_sub2(0);
print_sub3();
cout<<total<<endl;
}
system("PAUSE");
return 0;
}
1.增量构造法
2.位向量法
3.二进制法
增量构造法
基本思想:每次取一个元素加入集合中,再向新集合中加入剩余的元素
如求{1,2,3}的子集,假设集合中的元素按从小到大排列
1.首先选一个元素,集合可以依次选A1={1},B1={2},C1={3}
2.A1中加入一个元素,集合可以为A2={1,2},A3={1,3},
3.A2中加入一个元素,集合可以为A4={1,2,3},而A3中已经不能再添加元素
4.同理,B1、C1中也可以依次添加元素
实际上是一个递归的过程,首选循环取出一个元素A,以A开始再循环一个个取出剩下的元素B,相当于以B开始再重复这一过程,求子集的函数如下
void print_sub1(int cur)
{
int i, j;
for(i = 0;i < cur; i++)
cout<<set[i]+1<<" ";
cout<<endl;
total++;
/*
j是每次递归集合中的最小值
*/
j = cur?set[cur-1]+1:0;
for(i = j; i < n; i++){
set[cur] = i;
print_sub1(cur+1);
}
}
位向量法
构造子集的另一种方法是,对集合中的每一个数,我们可以选择取出或者不取,这样我们可以构造一个位向量数组bit,其下标对应集合中元素的位置,bit中的值为1表示对应的数组元素在子集中,为0则不在其中,这样我们就可以用递归方法实现
void print_sub2(int cur)
{
if(cur == n){
for(int i = 0;i < n; i++)
if(!bit[i]) cout<<i+1<<" ";
cout<<endl;
total++;
return;
}
//每一个数有取或不取两种选择
bit[cur] = 1;
print_sub2(cur+1);
bit[cur] = 0;
print_sub2(cur+1);
}
二进制法
受前一种方法的启发,可以把子集表示为0和1组成的串,{1,2,3}构造子集的过程如下:
321 321 321
321 ...... 321
001 010 011 100 ...... 111
1 2 12 3 ...... 123
只要一个整型数逐一递增再与相应元素按位与就可以枚举出所有的子集,但是该方法有一个缺陷,就是集合的个数不能大于在计算机中一个整型数的位数,一般为32位,算法如下:void print_sub3()
{
int i,j;
//子集的个数为2^n, 1<<n相当于1*2^n
for(i = 0; i<(1<<n); i++){
for(j = 0; j < n; j++){
if(i&(1<<j)) cout<<j+1<<" ";
}
cout<<endl;
total++;
}
}
完整算法:
#include <cstdlib>
#include <iostream>
using namespace std;
int set[20], n, total, bit[20];
void print_sub1(int cur)
{
int i, j;
for(i = 0;i < cur; i++)
cout<<set[i]+1<<" ";
cout<<endl;
total++;
/*
j是每次递归集合中的最小值
*/
j = cur?set[cur-1]+1:0;
for(i = j; i < n; i++){
set[cur] = i;
print_sub1(cur+1);
}
}
void print_sub2(int cur)
{
if(cur == n){
for(int i = 0;i < n; i++)
if(!bit[i]) cout<<i+1<<" ";
cout<<endl;
total++;
return;
}
//每一个数有取或不取两种选择
bit[cur] = 1;
print_sub2(cur+1);
bit[cur] = 0;
print_sub2(cur+1);
}
void print_sub3()
{
int i,j;
//子集的个数为2^n, 1<<n相当于1*2^n
for(i = 0; i<(1<<n); i++){
for(j = 0; j < n; j++){
if(i&(1<<j)) cout<<j+1<<" ";
}
cout<<endl;
total++;
}
}
int main()
{
while(cin>>n){
total = 0;
//print_sub1(0);
//print_sub2(0);
print_sub3();
cout<<total<<endl;
}
system("PAUSE");
return 0;
}
相关文章推荐
- ACM_子集生成算法总结
- 【算法学习笔记】14.暴力求解法02 子集生成的三种方法
- 按字典序生成{1,2,...,n}的r子集的算法-组合数学
- 最小生成树算法总结
- 子集生成算法——增量构造法
- 算法学习之子集生成问题
- 【算法学习笔记】14.暴力求解法02 子集生成的三种方法
- C++_子集生成算法汇总
- 分布式ID生成算法总结
- 子集生成算法
- uva 11205 The Broken Pedometer(经典的子集生成题目,在此总结了三种子集生成的方法~)
- 算法:子集生成
- 关于算法竞赛入门经典一书的思考学习——枚举排序和子集生成!
- 子集生成算法
- 【算法竞赛入门经典】7.3子集生成【增量构造法】【位向量法】【二进制法】
- 极限元算法专家:深度学习在语音生成问题上的典型应用 | 学术分享会总结文
- 子集生成算法
- 子集生成算法
- 子集生成算法
- 18-1-30~2~5一周算法总结(DP,二分图,最小生成树)