Algorithm 保持一组最小子集

Algorithm 保持一组最小子集,algorithm,data-structures,set,subset,Algorithm,Data Structures,Set,Subset,下面是我想在假设的集合数据结构上执行的操作,该结构将集合作为其元素: 在数据结构中插入一个集合,但是:(1)如果新集合是任何现有集合的超集,请不要添加它(2)如果新集合是任何现有集合的子集,请删除它们 枚举集合中当前的所有集合 所有讨论的集合都是已知有限集合的子集,比如{0..10^4} 有没有一种方法可以有效地做到这一点?枚举集合中的集合很容易,O(n)。然而,检查一个新的候选者是否是所有现有集合的子集会有点昂贵。如果一个集合是另一个集合的子集,有一些众所周知的算法可以测试,非常简单 for

下面是我想在假设的集合数据结构上执行的操作,该结构将集合作为其元素:

  • 在数据结构中插入一个集合,但是:(1)如果新集合是任何现有集合的超集,请不要添加它(2)如果新集合是任何现有集合的子集,请删除它们
  • 枚举集合中当前的所有集合
  • 所有讨论的集合都是已知有限集合的子集,比如{0..10^4}


    有没有一种方法可以有效地做到这一点?

    枚举集合中的集合很容易,O(n)。然而,检查一个新的候选者是否是所有现有集合的子集会有点昂贵。如果一个集合是另一个集合的子集,有一些众所周知的算法可以测试,非常简单

    for each subset s in S
        for each candidate set C
            test of C is a subset of s
            if it is, break
    if never found, add C to S.
    

    这将类似于O(n^2lgn)。这算是“有效”吗?

    为所有存储集维护一个bloom过滤器。为要插入的集合生成bloom过滤器。如果使用另一个集合的bloom筛选器按位和要插入的集合的筛选器(称为X)并获取值X,则要插入的集合可能是一个子集(可能是误报,此时需要检查慢速方式)。否则肯定不行,你可以试试另一个

    在构建bloom过滤器时,有许多可调整的参数,允许您在空间效率和误报概率之间进行权衡


    为了节省空间,可以使用位集表示已知有限集的每个子集。还有一些表示稀疏位集的方法(例如,请参见),以进一步节省空间


    整体结构可以是一组位集。在Java中,
    BitSet
    没有子集测试方法,但我认为扩展
    BitSet
    以包含有效的子集测试方法不会太难。(这将避免测试要添加的候选对象是否等于其与任何现有子集的交集的讨厌任务。)

    使用某种树结构

    将已排序的现有集合存储在Trie中。如果指向该节点的路径是现有集,则在每个节点上维护一个标志

    1要检查给定集是否是已存在集的超集,请执行以下操作:

    2移除给定集合的所有超集

    def remsuperset(节点,集合[N],集合c,N):
    如果setc==N+1:
    删除此节点(节点)上或下方的所有集合
    返回
    对于ch in node.child:
    如果ch
    3对于枚举集,只需遍历树,并且打印路径为\u set标志为True

    所有讨论的集合都是已知有限集合的子集,比如{0..10^4}

    我们称之为N=10^4。这是相当小的,这将被证明是有用的。假设你有s套

    “逻辑上”这意味着你有一个N*S矩阵

    您将已经拥有一组集合。在这个主要结构中有S集

    10^4足够小,您可以维护一个二级数据结构,该结构为每个N值存储它所在的集合列表。这个结构有点像主结构的转置。这可能是长度为N的向量,允许常量时间查找查找特定值所在的集合列表

    现在,当您添加一个新的集合时,可以使用这个二级结构来查找它的每个值所在的其他集合。例如,我们添加了一个值为2,5,10的新集合

    new_set = {2,5,10}
    
    二级结构告诉我们它们在哪些集合中:

     2 : {A,B,D}
     5 : {B,D}
    10 : {B}
    

    我们可以对这三个列表进行合并和排序,得到
    ABBBDD
    ,它不仅告诉我们它与哪些集合重叠,还告诉我们重叠的大小。三个节点与B共享,这意味着我们的新集合是B的子集或等于B。我们与a共享一个节点,与D共享两个节点。如果结果表明a的总大小为1,那么我们现在知道a是新集合的子集。

    这是一篇关于这个问题的最新论文:


    简而言之,在最坏的情况下,你不能比二次时间做得更好;但在实践中,有一些技巧可以加快速度。

    什么是“高效”?你有什么具体的限制吗?如果你在结构中有一大堆集合,然后在结构中添加所有集合的超集,会发生什么?它会删除旧的吗?嗯,我正在探索一种可能的约束解决技术。大致的想法是约束求解器在搜索过程中尝试学习新的约束。这样做的问题是,随着大量约束的添加,约束数据库变得非常大且缓慢。许多约束是多余的。如果一个约束是另一个约束的超集(粗略地说),那么它是多余的。我想要一个只维护最小子集的数据结构。没有固定的限制;越快越好,因为约束求解器将能够处理更大的问题。@templatetypedef:是的,准确地说:)我忘了在问题中提到这一点;我现在要加上,这是蛮力法。我希望有更有效的办法;)我现在没有时间或空间来尝试写一个证明,但我怀疑O(n^2lgn)是最佳的。我不认为你能使外循环比O更好(| S |*C候选数),我也不认为你能在小于O(lgn)的情况下测试子集。我认为接下来的证明是矛盾的。这个论点只是表明没有明显的方法来改进你的算法。为什么不能有一个完全不同的算法呢?事实上,在次二次时间上,似乎有更好的算法(参见福克·胡夫纳的答案或“寻找极值集的旧次二次算法”)。朱尔斯,当有人说“我怀疑,但我现在不能写证明”时,这意味着“但我可以”
    new_set = {2,5,10}
    
     2 : {A,B,D}
     5 : {B,D}
    10 : {B}