子集生成算法 之 位向量法和增量构造法
2016-11-14 01:19
941 查看
什么是子集生成?
算法竞赛经典入门中的解释:给定一个集合,枚举所有的可能的子集。位向量法
1.什么是位向量法?
通过构造一个标记向量pd[i],而不直接构造存放题目数据的子集A。
当pd[i]==true的时候,标记了了我们把数据集合中的第i个位置的数据放入一个子集中,这一切都是通过标记数组pd[]来实现的。
2.原理图
#include<iostream> #include<stdio.h> using namespace std; int n; int k1[10]; bool pd[10]; void vec_cl (int cur) { if (cur != 0) { for (int i=0;i<n;i++) { if (pd[i] == true) { cout<<k1[i]; } } cout<<endl; } if (cur == n)//设置递归出口,证明此时已经到达数据边界,开始弹出系统栈 return ; for (int i=0;i<n;i++) { if (pd[i] == false) { pd[i] = true;//进行标记,表明此时数据已经在一个未知名的子集中存放 vec_cl (i+1); pd[i] = false;//进行标记,表明此时子集已经输出完毕,开始找新的子集,同时要进行一个恢复原数据状态的操作 } } } int main () { while (cin>>n) { memset(k1,0,sizeof(k1)); memset(pd,false,sizeof(false)); for (int i=0;i<n;i++) { cin>>k1[i]; } vec_cl (0); } return 0; }
执行结果:
优点:
相比于其他两种算法(增量构造法,二进制法),这种算法理解起来比较容易
缺点:
相比于其他两种算法,此种算法效率不够,我们需要访问解答树中的所有的节点,不满足我们设定的特定条件的节点也被访问了,这点我归纳为这是暴力求解法的一种算法。
增量构造法
1.什么是增量构造法
在一次操作中尽量准确从集合A中,筛选出一个符合我们设置条件的元素,并放入一个新的集合中,构造一个子集B。
2.原理图
#include<iostream> #include<stdio.h> using namespace std; int n; int k1[10];//存放具体数据 int pos[10];//存放每次查找下一个元素的在集合k1中元素的具体位置 void add_cl (int cur)//从一定程度上,我们可以这么理解cur参数:即cur是我们进行图的遍历的层数 { if(cur != 0) { for (int i=0;i<cur; i++) { cout<<k1[pos[i]]; } cout<<endl; } int dingwei = cur ? pos[cur-1] + 1 : 0; //这句对于大多数人来说比较晦涩难懂,下面注释部分为这句的较为通俗的写法 //上面一句就是这个算法的核心------->> 我们的集合pos其实存放的数据是满足我们设置的一定条件的集合k1中的元素的具体位置 //我们通过一些条件控制到达了避过一部分已经找到的子集目的,有效的过滤了不满足条件的集合,增加了我们进行了递归操作的效率 /* if (cur == 0) { dingwei = 0; } else { dingwei = pos[cur-1] + 1; } */ for (int i=dingwei;i<n;i++) { pos[cur] = i; add_cl(cur+1); //这个算法的一个好处:我们不用特别的判断递归条件,因为我们进行的数组的遍历,我们通过循环无形中进行了控制, //也就是说在此时这个for循环的工作空间内,进行了添加数据的操作,如果不满足这个for循环的条件,我们就可以这么认为:无法添加新的元素,自然也就不会有递归了 } } int main () { while (cin>>n) { memset(k1,0,sizeof(k1)); memset(pos,0,sizeof(pos)); for (int i=0;i<n;i++) { cin>>k1[i]; } add_cl (0); } return 0; }优点:
有效的控制了递归的运行效率,我们不用访问解答树的每一个节点,能比较快的查找下一个元素所在的位置
在特定的要求下,我们能进行比较好的条件控制,下面我会举一个例子。
缺点:
比较抽象,有一点回溯的思想,我们也可以抽象成图的思想(毕竟树结构也是图的一个分支),如果理解这个算法,对于回溯会有比较好的理解。
我们举一个例子:
当我们设置条件,比如:我想要包含两个元素的子集
我们的代码就可以这么书写:
#include<iostream> #include<stdio.h> using namespace std; int n; int k1[10],pos[10]; void cl (int cur) { if (cur==2) { for (int i=0;i < cur ;i++) { cout<<k1[pos[i]]; } cout<<endl; } int dingwei = 0; if (cur == 0) { dingwei = 0; } else { dingwei = pos[cur-1] + 1; } for (int i=dingwei; i<n;i++) { pos[cur] = i; cl(cur+1); } } int main () { while (cin>>n) { memset(k1,0,sizeof(k1)); for (int i=0;i<n;i++) { cin>>k1[i]; } memset(pos,false,10); cout<<"查看初始化的数组k1"<<endl; for (int i=0;i<10;i++) { cout<<k1[i]; } cout<<endl; cl(0); } return 0; }
关于子集生成算法的二进制法,由于本人愚笨,还没有更好的领悟,只好在下一次更新中写出来分享给大家。
对于上面这两种算法,如果有不对或者有更好的优化,请各位在评论区下面写出来,让我们共同进步。
相关文章推荐
- 【算法竞赛入门经典】7.3子集生成【增量构造法】【位向量法】【二进制法】
- 子集生成算法——增量构造法
- 子集生成的两种方法 (增量构造法 和 位向量法)
- 暴力求解法_子集生成(增量构造法,位向量法,二进制法)
- 子集生成 增量构造法 位向量法 二进制法
- 枚举子集 增量构造法 位向量法 二进制法
- 子集生成之增量构造法(允许有重复元素)
- [Day 1] 7.3.1 子集生成-增量构造法
- 算法学习之子集生成问题
- ACMjava子集生成的三种方法,增量构造,辅助位向量,二进制法
- 算法分析与设计-减治法3:生成子集的减治算法及二进制法
- 子集生成(位向量法)
- 算法--生成子集
- C++_子集生成算法汇总
- 子集生成算法
- ACM_子集生成算法总结
- 子集生成算法
- 子集生成算法
- 入门经典 第七章 7.3.1 增量构造生成子集
- 子集生成算法合集