子集生成问题

来源:互联网 发布:ios 软件 目录 编辑:程序博客网 时间:2024/06/05 21:04

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

方法一:

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

#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,否则为0int 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;}



0 0
原创粉丝点击