检查子集是否包含给定子集列表的快速方法
fast way to check if subset contains a given list of subsets
我的问题如下
我有一个K元素的集合这个集合的每个子集都由std::bitset的一个实例表示(第i位为真=子集中存在第i个元素)
我有一个输入子集I和一个子集列表S1…Sn
我想从S1返回项目…Sn,使得Si包含在I中(也就是说,每次Si有一个位为真,它在I中也必须为真)
显然,这可以在K*n内完成,通过对每个S子集独立地进行相同的检查。
然而,有没有一种通用的方法可以做得更好?我很确定这是可能的,因为在我的情况下,子集列表S1…Sn总是相同的,可以进行预处理。我确信可以将子集存储在特定的数据结构(树?),这样我就可以一次丢弃很多相同的东西,等等
example :
K = 5
I = [1,1,0,1,0]
S1 = [1,0,0,0,0]
S2 = [1,1,0,1,0]
S3 = [1,1,1,0,0]
the ouput should return S1,S2 (not S3!)
我有一个常数集S1,S2,...,Sn
,并且在相同的集合上运行I
的不同查询。
编辑:我所说的例子:例如,如果S1包含在S2中:检查S1是否包含在I中:如果没有,则S2不能包含在I中(不需要检查)如果S3是S1和S2的并集:如果S1和S2包含在I中,那么S3
构造一个二叉树T
与所有S1...Sn
,其中每一级k有两个子节点,取决于S
是否有0
或1
在位置k
。树的叶子都是你的S1...Sn
。
给定一个输入子集I
,让我们取Ik
(位置k的元素):如果Ik==0
,则选择T
在K
对应的0层的子树。如果Ik==1
,则选择T
在K
级别的两个子树。以这种方式在T上进行,直到到达所有的叶子。
在最坏的情况下,对给定的
I
进行O(n+k)
操作
由于S1...Sn
不会改变,构造树T
是一次操作。
T
有不止n
片叶子,它有2^k=m
片叶子。但是我们可以移除不在S1...Sn
中的叶子和死子树。这带来了O(2^k)
的成本分析,但实际上我们将拥有更少的节点。现在分析变得更加困难,是否值得取决于m
和n
之间的比率;
我提出了一种不同的分析方法:认为在k级上,我们在恒定时间内丢弃k
级上具有无效位的所有子集S
,但我们必须在每级O(n)
子树中这样做。由于该操作重复了k
次,因此最大成本将是O(kn)
,但实际上平均成本更低。
您可以使用倒排索引方法。虽然它不能提高最坏情况下的性能,但它可能会加快平均情况下的速度,特别是对于相对密集的查询向量。
对于每个j=1,2,…,k创建一个排序列表,如果j
在S_i
中,则每个子集都在此列表中。它只在预处理中创建一次。
在您的示例中,它将类似于:
0 -> [S1,S2,S3]
1 -> [S2,S3]
2 -> [S3]
3 -> [S2]
4 -> []
现在,给定一个查询I
,找出包含I
的一个"down"位的所有集合。这与信息检索中的OR查询相同。这个查询的答案是结果中没有的子集。
在您的示例中,查询的是2 OR 4
,查询倒排索引的结果是:S3
,因此结果是S1,S2。
这基本上是搜索引擎所做的,如果查询包含的术语很少,与可能的数量相比,它是非常有效的。
用部分答案回答我的问题:
- 从S1
- …然后我们构建一个子集树,使得根节点是空子集(bitset中全部为0),并且使得每个子节点都包含它的父子集
- 对于算法,从根节点开始:
- 每个孩子的
- :
- 如果该节点的子集包含在I中,则添加该子集并以该节点为根再次调用算法
- 否则,转到下一个子树(此子树的子树永远不会被处理)
- :
现在的问题是,如何从1)最优地构建树?它具有最大深度和最小"宽度"。例如,在我的示例中,"坏"树是S1、S2和S3是根节点的子节点。一个"好的"树应该是根节点只有S1作为子节点,而根在S1的树有S2和S3作为子节点。我不知道如何构建这棵树,但是
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 为什么我的子集和方法不正确?
- 类方法子集的惰性评估
- 通过其方法的子集实现接口
- 将函子应用于设备数组的子集的最有效方法是什么
- 将函数应用于向量子集的最佳方法是什么
- 确定一个向量是否是另一个向量的子集的有效方法
- 从一组集合中找到集合子集的最佳方法
- 类方法子集的编译时生成
- 在 C/C++ 中子集'every other bits'的最简单方法是什么?
- 检查子集是否包含给定子集列表的快速方法
- 获取std::set子集的有效方法