您的位置:首页 > 其它

子集生成-复杂状态的动态规划(集合dp)预热

2015-12-09 12:02 302 查看
子集生成的3种方法

1.增量构造法,枚举1到n的所有可能集合。

#include<iostream>
using namespace std;

void print_subset(int *A,int n,int cur)
{
for(int i = 0;i <cur;++ i)  //打印当前集合
cout << A[i] << ' ';
cout << endl;
int s = cur ? A[cur - 1]: 0;
for(int i = s;i < n; ++ i)
{
A[cur] = i+1;
print_subset(A,n,cur + 1);
}
}

int main()
{
int n;
cout<<"输入n,产生集合1到n中所有的子集。"<<endl;
while(cin >> n)
{
int *A=new int[n + 1];
for(int i = 0;i <n;++ i)
A[i] = i+1;
print_subset(A,n,0);
}
return 0;
}
精髓 int s = cur ? A[cur - 1]: 0;

还是在程序实现能力太弱。光理解就用了半天.........

解释:比如1到n。先是1,然后从1开始放一个元素(for循序递归过程)...。输出形如1 2 3..., 1 3 4....,等等.然后是2.。同理....

2.位向量法

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=10000;
int A[maxn];

void print_subset(int *B,int n,int cur)
{
if(cur==n)
{
for(int i=0;i<n;i++)
{
if(B[i])
{
printf("%d ",A[i]);
}
}
printf("\n");
return;
}
B[cur]=1;
print_subset(B,n,cur+1);
B[cur]=0;
print_subset(B,n,cur+1);
}

int main()
{
int n;
cout<<"输入n,产生集合1到n中所有的子集。"<<endl;
while(cin >> n)
{
int B[maxn];
for(int i = 0;i <n;++ i)
A[i] = i+1;
memset(B,0,sizeof(B));
print_subset(B,n,0);
}
return 0;
}


挺好理解的,就是每一个元素可以选择可以不选择,用一个B数组来记录。dfs。

3.二进制法。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=10000;
int A[maxn];

void print_set(int n,int s)
{
int flag=1;
for(int i=1;i<=n;i++)
if(s&(1<<i)&&(s&1))
{
printf("%d ",i);
flag=0;
}
if(!flag)
printf("\n");
}

int main()
{
int n;
cout<<"输入n,产生集合1到n中所有的子集。"<<endl;
scanf("%d",&n);
for(int i=0;i<(1<<(n+1));i++)
print_set(n,i);
return 0;
}


挺好理解的。一共有2^n种可能,枚举这2^N个数,然后再循环与(1<<n)&运算。

书上面是0到n-1,我这里是1到n。不同的就是在循环的时候不仅要判断s&(1<<i),还有加一个s&1或者s&0.不然就重复2次了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: