子集生成算法 之 位向量法和增量构造法

什么是子集生成?

算法竞赛经典入门中的解释:给定一个集合,枚举所有的可能的子集。
位向量法
1.什么是位向量法?
通过构造一个标记向量pd[i],而不直接构造存放题目数据的子集A。
当pd[i]==true的时候,标记了了我们把数据集合中的第i个位置的数据放入一个子集中,这一切都是通过标记数组pd[]来实现的。
2.原理图
子集生成算法 之 位向量法和增量构造法_第1张图片
#include
#include
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)
	{
		memset(k1,0,sizeof(k1));
		memset(pd,false,sizeof(false));
		for (int i=0;i>k1[i];
		}
		vec_cl (0);
	}
	return 0;
}

执行结果:
子集生成算法 之 位向量法和增量构造法_第2张图片


优点:
  • 相比于其他两种算法(增量构造法,二进制法),这种算法理解起来比较容易
缺点:
  • 相比于其他两种算法,此种算法效率不够,我们需要访问解答树中的所有的节点,不满足我们设定的特定条件的节点也被访问了,这点我归纳为这是暴力求解法的一种算法。

增量构造法
1.什么是增量构造法
在一次操作中尽量准确从集合A中,筛选出一个符合我们设置条件的元素,并放入一个新的集合中,构造一个子集B。
2.原理图
子集生成算法 之 位向量法和增量构造法_第3张图片

#include
#include
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> 我们的集合pos其实存放的数据是满足我们设置的一定条件的集合k1中的元素的具体位置
	//我们通过一些条件控制到达了避过一部分已经找到的子集目的,有效的过滤了不满足条件的集合,增加了我们进行了递归操作的效率

	/*
		if (cur == 0)
		{
			dingwei = 0;
		}
		else
		{
			dingwei = pos[cur-1] + 1;
		}
	
	*/
	for (int i=dingwei;i>n)
	{
		memset(k1,0,sizeof(k1));
		memset(pos,0,sizeof(pos));
		for (int i=0;i>k1[i];
		}
		add_cl (0);
	}
	return 0;
}
优点:
  • 有效的控制了递归的运行效率,我们不用访问解答树的每一个节点,能比较快的查找下一个元素所在的位置
  • 在特定的要求下,我们能进行比较好的条件控制,下面我会举一个例子。
缺点:
  • 比较抽象,有一点回溯的思想,我们也可以抽象成图的思想(毕竟树结构也是图的一个分支),如果理解这个算法,对于回溯会有比较好的理解。
我们举一个例子:
当我们设置条件,比如:我想要包含两个元素的子集
我们的代码就可以这么书写:
#include
#include
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<>n)
	{
		memset(k1,0,sizeof(k1));
		for (int i=0;i>k1[i];
		}
		memset(pos,false,10);
		cout<<"查看初始化的数组k1"<

关于子集生成算法的二进制法,由于本人愚笨,还没有更好的领悟,只好在下一次更新中写出来分享给大家。

对于上面这两种算法,如果有不对或者有更好的优化,请各位在评论区下面写出来,让我们共同进步。


你可能感兴趣的:(ACM练习)