子集生成:给定一个集合,枚举它所有可能的子集。(简单起见,这里假设集合中没有重复元素)
思路:一次选出一个元素放到集合中。
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位置元素的最小可能值。
解答树对应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) {//只有当"所有元素是否选择"全部确定后,才是一个完整的子集 for(int i=0;i<cur;++i) if(B[i]) printf("%d ",A2[i]); printf("\n"); return ; } B[cur]=1;//第cur个元素选取 print_subset2(n,B,cur+1); B[cur]=0;//第cur个元素不选取 print_subset2(n,B,cur+1); }其中函数前半部分的 if 语句也是用于输出一个子集。后面代码用于确定选择或不选择第cur个元素。
只有当cur==n时,即所有元素是否选择都确定后,才是一个完整的子集,才输出。
解答树上有2的n+1次方-1个结点。即1+2+4+8+...+2^n=2^(n+1)-1
思路:从右往左第 i 位表示元素 i 是否在子集中。二进制110表示子集{2,1}。(各位从0开始编号,即最右是0号位)
异或运算的开关性:异或两次以后相当于没有异或,即A^B^B=A.
A&B、A|B、A^B 对应集合的交、并和对称差。空集为0,全集{0,1,2,...,n-1}的二进制为全1,即十进制的2^n-1。往往在程序中把全集定义为ALL_BITS=(1<<n)-1,则A的补集为ALL_BITS^A。
Code:
void print_subset3(int n,int s) {//输出子集对应的各个元素 for(int i=0;i<n;++i) if(s&(1<<i)) printf("%d ",i);//1对应输出0,2对应1,3对应01,4对应2 printf("\n"); } //枚举子集 for(int i=0;i< (1<<n);++i) print_subset3(n,i);
下面是可以直接运行的程序,其中前两种方法从1开始编号,第三种方法从0开始编号,生成子集。
#include<stdio.h> #include<stdlib.h> void print_subset1(int n, int *A, int cur); void print_subset2(int n, int *B, int cur); void print_subset3(int n,int s); int A[10]; int A2[]={1,2,3,4,5,6,7,8,9,10}; int B[10]; int main() { /*printf("增量构造法:\n"); print_subset1(10,A,0); system("pause"); printf("位向量法:\n"); print_subset2(10,B,0); system("pause");*/ printf("二进制法:\n"); int n=10; for(int i=0;i<(1<<n);++i){ print_subset3(n,i); system("pause");} return 0; } 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 :1;//确定当前元素的最小可能值 for(int i=s;i<n+1;++i) { A[cur]=i; print_subset1(n,A,cur+1);//递归构造子集 } } void print_subset2(int n, int *B, int cur) {//位向量法 if(cur==n) {//只有当"所有元素是否选择"全部确定后,才是一个完整的子集 for(int i=0;i<cur;++i) if(B[i]) printf("%d ",A2[i]); printf("\n"); return ; } B[cur]=1;//第cur个元素选取 print_subset2(n,B,cur+1); B[cur]=0;//第cur个元素不选取 print_subset2(n,B,cur+1); } void print_subset3(int n,int s) {//输出子集对应的各个元素 for(int i=0;i<n;++i) if(s&(1<<i)) printf("%d ",i); printf("\n"); }
原文地址:http://blog.csdn.net/buxizhizhou530/article/details/43952075