子集生成——增量构造法+位向量法+二进制法

Posted graytido

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了子集生成——增量构造法+位向量法+二进制法相关的知识,希望对你有一定的参考价值。

1.增量构造法:

原理图:

技术图片

 

 1 // 此算法仅用于输出下标,实际运用应输入另一个数组来进行数据的储存
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 typedef long long ll;
 5 typedef unsigned long long ull;
 6 #define INF 0X3f3f3f3f
 7 const ll MAXN = 1e3 + 7;
 8 const ll MOD = 1e9 + 7;
 9 int a[10];
10 void print_subset(int n,int cur)//cur相当于遍历图的层数
11 {
12     for(int i=0;i<cur;i++) cout<<a[i];
13     cout<<endl;
14     // 找到当前子集的第一个元素
15     int s=cur?a[cur-1]+1:0;//确定当前元素的最小可能值
16     /* 这一句很难懂,实际上就是相当于下面的代码
17     int s;
18     if(cur==0) s=0;
19     else s=a[cur-1];
20      */
21     for(int i=s;i<n;i++)
22     {
23         a[cur]=i;
24         //当前层子集第一个值
25         //cur+1表示当前层值设置完毕,开始递归下一层,和前面步骤一样。
26         //到达最后一层结束后return 到上一层,然后i++,a[cur]的值(首元素)改变,又反复递归下一层
27         print_subset(n,cur+1);
28     }
29     return ;
30 }
31 int main()
32 {
33     print_subset(4,0);
34     system("pause");
35     return 0;
36 }

 

 2.位向量法:

构造一个位向量,而不是直接构造子集本身

位向量的解答树如图:

技术图片

 1 // 此算法仅用于输出下标,实际运用应输入另一个数组来进行数据的储存
 2 // 在枚举子集的位向量法中,解答树的结点掠夺,但在多数情况下仍然够快
 3 #include <bits/stdc++.h>
 4 using namespace std;
 5 typedef long long ll;
 6 typedef unsigned long long ull;
 7 #define INF 0X3f3f3f3f
 8 const ll MAXN = 1e3 + 7;
 9 const ll MOD = 1e9 + 7;
10 int a[10];
11 void print_subset(int n, int cur)
12 {
13     if (cur == n)
14     {
15         for (int i = 0; i < cur; i++)
16             if (a[i]) cout << i;
17         cout << endl;
18         return;
19     }
20     a[cur]=1;//选第cur个元素
21     print_subset(n,cur+1);
22     a[cur]=0;//不选第cur个元素
23     print_subset(n,cur+1);
24 }
25 int main()
26 {
27     print_subset(4, 0);
28     // system("pause");
29     return 0;
30 }

3.二进制法:

还可以用二进制来表示{0,1,2······,n-1}的子集S:从右往左第i位(各位从0开始编号)表示i是否在集合S中,图中展示了二进制0100011000110111是如何表示集合{0,1,2,4,5,9,10,14}的

技术图片

 

 1 //此算法仅仅是输出下标,实际应用应输入另一个数组来进行存储数据
 2 //原理:用数字的二进制位表示状态,二进制从右到左的第几个位置 表示数组元素的下标
 3 #include <bits/stdc++.h>
 4 using namespace std;
 5 typedef long long ll;
 6 typedef unsigned long long ull;
 7 #define INF 0X3f3f3f3f
 8 const ll MAXN = 1e3 + 7;
 9 const ll MOD = 1e9 + 7;
10 void print_subset(int n, int s) 
11 {
12     //s代表的是当前二进制数表示的状态
13     for(int i = 0; i < n; ++i) 
14         if(s & (1 << i)) //1右移几位就代表第i个二进制位为1,其他位为0,与状态进行&运算,如果此状态包含该数字,就输出
15             cout<<i;
16     cout<<endl;
17 }
18 int main() 
19 {
20     int n;
21     while(cin>>n) 
22     {
23         //一共n个数字,所以其全集有2^n个二进制1,所对应的十进制数字就是2^n - 1
24         //我们要做的就是枚举出来每一种状态,1 右移 n 位,所得的十进制数字就是2^n
25         for(int i = 0; i < (1 << n) ; ++i)       //i表示集合元素的状态,根据该状态打印出当前集合
26             print_subset(n, i);
27     }
28     return 0;
29 }

 

以上是关于子集生成——增量构造法+位向量法+二进制法的主要内容,如果未能解决你的问题,请参考以下文章

『模板』 子集生成

生成子集 (增量构造法)

构造增量法生成子集

子集生成——增量构造法

暴力求解法——子集生成(位向量法)

暴力求解法——子集生成(位向量法)