C++ 给定一组正整数<=k和它的n个子集,求哪对子集的并集给出原始集

C++ 给定一组正整数<=k和它的n个子集,求哪对子集的并集给出原始集,c++,algorithm,set,C++,Algorithm,Set,我有一个集合a,它由第一个p个正整数(1到p)组成,并且我得到了这个集合的n个子集。我怎样才能找到并集上有多少对子集会给出原始集合A 当然,这可以通过检查每对的并集的大小来实现,如果它等于p,则并集必须组成集合A,但是有没有更优雅的方法来实现这一点,从而降低时间复杂性 > C++中的SETION结合具有时间复杂度>2*(大小(set 1)+大小(set 2))-1 < /C> >对于NC2对不好。 < P>如果我们需要处理最坏的情况,则对这个问题的一些想法: 我认为使用std::bitset而

我有一个集合a,它由第一个p个正整数(1到p)组成,并且我得到了这个集合的n个子集。我怎样才能找到并集上有多少对子集会给出原始集合A

当然,这可以通过检查每对的并集的大小来实现,如果它等于p,则并集必须组成集合A,但是有没有更优雅的方法来实现这一点,从而降低时间复杂性


<> > C++中的SETION结合具有时间复杂度>2*(大小(set 1)+大小(set 2))-1 < /C> >对于NC2对不好。

< P>如果我们需要处理最坏的情况,则对这个问题的一些想法:

  • 我认为使用
    std::bitset
    而不进行任何优化就足以完成此任务,因为union操作要快得多。但如果不是,不要使用可变大小的向量,使用简单的p长度0-1数组/向量或无序的_集。我不认为在最坏的情况下,没有O(1)find操作的可变大小向量会更好

  • 使用启发式最小化子集联合。最简单的启发式方法是检查子集的大小。我们只需要
    大小(A)+大小(B)>=p的子集的
    (A,B)

  • 除了启发式,我们还可以计算(在
    O(n^2)
    中)每个数字在子集中出现的频率。然后,我们可以按频率递增顺序检查某些子集中的数字是否存在。此外,我们可以排除出现在每个子集中的数字

  • 如果要修复某个子集
    A
    (例如,在外部循环中),并找到与其他子集中的联合,则只能检查集合
    A
    中未显示的数字。如果子集
    A
    足够大,则可以显著减少所需的操作数量


  • 这只是对您的方法的一个可能的改进,您可以保留一个布尔数组,而不是二进制搜索,以确定是否有一些x出现在O(1)中的数组i

    比如说,, 比如说,在获取输入时,您保存了数组i的所有外观。也就是说,如果数组i中出现x,则isThere[i][x]应为true,否则为false


    这可以节省一些时间。

    我几乎可以肯定这是一个np问题。
    p
    有任何限制吗?@DAle p可以高达10^3您提到的
    k
    是什么?你的意思是
    p
    ?@DanielJour如果我正确理解洞,如果S1={1,3,4,5,6,7,8,9,10}有一个洞(2个不存在),S2={1,2,4,6,8,9,10}有3个洞,那么即使我根据你建议的第4点构建了我的算法,联合也会产生完整的集合。我在外循环中固定了一个子集,并在两个子集中对1到p进行了二进制搜索。同时保存固定子集中出现的整数,以便在需要时不必再次进行二进制搜索,我认为trickI得到了它,您将创建一个2D布尔数组,但这样的数组必须为每个子集保存,并且假设我有10^5个平均长度为100的子集,这是不可行的,不是吗?这就是我只为当前外循环子集保存一个数组的原因。bro,忘记最大大小,将每个对应布尔数组的平均大小设为100(因此子集的大小),您可以有2^p子集,因此您需要在最坏情况下存储长度为100的2^p数组。。。