求解幂集问题
幂集是集合的基本运算之一,由集合的所有子集构成的集合。例:n=3时,幂集是:
{{},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}};
若是有限集,有n个元素,那么的幂集有2^n个元素.
【问题描述】
对于给定的正整数n(n≥1),求1~n构成的集合的所有子集(幂集).
【问题求解】
●蛮力法①
采用直接蛮力法求解,将1~n的存放在数组a中,求解问题变为构造集合a的所有子集,设集合a[0…2]={1,2,3},其所有子集对应的二进制位及其十进制数如下。
<1>.对于含有n(n≥1)个元素的集合a,求幂集的过程如下:
for(i=0;i<2^n;i++)
{
将i装换为二进制数b;
输出b中为1 的位对应的a 元素构成一个子集;
}
<2>.首先b[0…2]=000,每调用一次inc,b表示的十进制数增加1
算法如下:
void inc(int b[],int n) //将b表示的二进制数增1
{
for(int i=0;i<n;i++) //遍历数组b
{ if(b[i]) //将元素1改为0
b[i]=0;
else //将元素0改为1并退出for循环
{ b[i]=1;
break;
}
}
}
解释如下:
【完整算法代码】
#include<stdio.h>
#include<math.h>
void inc(int b[],int n) //将b表示的二进制数增1
{
for(int i=0;i<n;i++) //遍历数组b
{ if(b[i]) //将元素1改为0
b[i]=0;
else //将元素0改为1并退出for循环
{ b[i]=1;
break;
}
}
}
void PSet(int a[],int b[],int n) //求幂集
{ int i,j;
int pw=(int)pow(2,n); //求2^n
printf("1~%d的幂集:\n",n);
for(i=0;i<pw;i++) //执行2^n次
{
printf(" { ");
for(int k=0;k<n;k++) //执行n次
if(b[k])
printf("%d",a[k]);
printf(" } ");
inc(b,n); //b表示的二进制数增1
}
printf("\n");
}
int main(){
int n=3;
int a[10],b[10];
for(int i=0;i<n;i++)
{
a[i]=i+1;
b[i]=0;
}
PSet(a,b,n);
}
时间复杂度:O(n*2^n)
●增量蛮力法②
采用增量蛮力法求解1~n的幂集,当n=3是的求解过程。
这种思路也是蛮力法求解:穷举1~n的所有子集。对应的过程如下:
void f(int n) //求1~n的幂集ps
{
置ps={{}}; //在ps中加入一个空子集元素
for(i=1;i<=n;i++)
{
ps1=ps;
在ps1的每个子集元素中添加i;
将ps1的所有元素添加到ps中;
}
}
【完整算法代码】
#include<stdio.h>
#include<vector>
using namespacestd;
vector<vector<int>> ps; //用于存放幂集
void Pset(int n){
vector<vector<int> > ps1; //子幂集
vector<vector<int> >::iterator it; //迭代器
vector<int> s; //添加空集元素
ps.push_back(s);
for(int i=1;i<=n;i++){
ps1=ps; //ps1存放上一步骤得到的幂集
for(it=ps1.begin();it!=ps1.end();++it)
(*it).push_back(i); //在ps1的每个集合元素末尾添加i
for(it=ps1.begin();it!=ps1.end();++it)
ps.push_back(*it); //将ps1的每个集合元素添加到ps中
}
}
时间复杂度:O(2^n)