枚举-子集生成法1

紫书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 }
posted @ 2020-01-15 17:38  SavenNeer  阅读(146)  评论(0编辑  收藏  举报