子集生成:给定一个集合,枚举它所有可能的子集。(简单起见,这里假设集合中没有重复元素)
一、增量构造法
思路:一次选出一个元素放到集合中。
Code:
void print_subset1(int n, int *A, int cur)
{//增量构造法
for(int i=0;i<cur;++i)
printf("%d ",A[i]);
printf("\n");
int s=cur ? A[cur-1]+1 :0;//确定当前元素的最小可能值
for(int i=s;i<n;++i)
{
A[cur]=i;
print_subset1(n,A,cur+1);//递归构造子集
}
}
其中函数开始部分三行是用于输出一个子集的。s 变量用于确定当前cur位置元素的最小可能值。
上面的代码用到了定序的技巧,规定集合中所有元素的编号从小到大排列,就不会把集合{1,2}安装{1,2}和{2,1}输出两次了。
解答树对应2的n次方个结点。每个可能的A都对应一个结点,而n个元素恰好有2的n次方个子集。相比于方法2,即不存在部分解。
二、位向量法
思路:构造一个位向量B[i],而不是直接构造子集A[i]本身,B[i]标记元素 i 在子集A中。
Code:
void print_subset2(int n, int *B, int cur)
{//位向量法
if(cur==n)
{//只有当"所有元素是否选择"全部确定后,才是一个完整的子集