您的位置:首页 > 其它

算法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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息