紫书P188-7.3子集生成
1、增量构造法
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int aim[100]; 5 int psd[100];//核心代码如下 6 int subset(int cur,int n,int last)//必须使用last元素记录上层函数添加的最后一个元素的序号 7 { 8 for(int i=0;i<cur;i++) 9 printf("%d ",aim[i]); 10 printf("\n"); 11 int k=last+1; 12 for(;k<n;k++) 13 { 14 aim[cur]=psd[k]; 15 subset(cur+1,n,k); 16 } 17 return 0; 18 } 19 20 int main() 21 { 22 int n; 23 scanf("%d",&n); 24 for(int i=0;i<n;i++) 25 scanf("%d",&psd[i]); 26 subset(0,n,-1);//初值从-1开始,因为递归中的循环时从last+1开始 27 return 0; 28 }
这是最为常用的一种方法,其思路来源于C++中"枚举法全排列"的函数设计思路。
2、位向量法
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int aim[100]; 5 int psd[100]; 6 //该代码的核心是利用aim中的0与1情况不同间接地对psd中的值进行挑选 7 int subset(int cur,int n) 8 { 9 if(cur==n) 10 { 11 for(int i=0;i<n;i++) 12 if(aim[i])printf("%d ",psd[i]); 13 printf("\n"); 14 } 15 else 16 { 17 aim[cur]=1; 18 subset(cur+1,n); 19 aim[cur]=0; 20 subset(cur+1,n); 21 } 22 return 0; 23 } 24 //其显著的缺点就是分支太多,递归太多,但多数情形下并没有显著的影响 25 26 int main() 27 { 28 int n; 29 scanf("%d",&n); 30 for(int i=0;i<n;i++) 31 scanf("%d",&psd[i]); 32 memset(aim,0,sizeof(aim)); 33 subset(0,n); 34 return 0; 35 }
3、二进制法(从代码量的角度而言,这是最简单的方法)
该方法需要有逻辑运算与位运算基础,将单独说明.以下暂时只给出代码
->在用二进制表示子集时,位运算中的按位与、或、异或对应集合中的交、并和对称差。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 //以下代码用来打印{0,1,2~n-1}集合的子集 5 void subset(int n,int s) 6 { 7 for(int i=0;i<n;i++) 8 if(s&(1<<i))printf("%d ",i); 9 //非0即真 10 printf("\n"); 11 } 12 13 int main() 14 { 15 int n; 16 scanf("%d",&n); 17 //枚举各子集对应的编码为0到2^n-1 18 for(int i=0;i<(1<<n);i++) 19 subset(n,i); 20 return 0; 21 }
原文:https://www.cnblogs.com/savennist/p/12197930.html