【问题标题】:find all possible subsets satisfying a predicate找到满足谓词的所有可能子集
【发布时间】:2021-03-30 06:58:05
【问题描述】:

我有一个由 N 个元素组成的集合 S。每个元素由一串长度为 L 的位表示。 例如,当 L=5 时,S 可以由{ 01010, 01100, 10100, 00001 } 组成

如果一对元素没有任何共同位(即如果它们的按位与为零),则它们是兼容的。例如:

  • 01010 与 01100 不兼容,因为01010 & 01100 = 01000(非零)
  • 01010 与 10100 兼容,因为01010 & 01010 = 00000(零)

如果 S 的所有元素的成对按位与为零,则 S 的子集是兼容的。 例如,子集{ 01010, 10100, 00001 } 是兼容的,因为以下所有陈述都是正确的

 01010 & 10100 = 0
 01010 & 00001 = 0
 10100 & 00001 = 0

我想找到 S 的所有可能兼容的子集。 鉴于上述 S 的示例,这将是:

{ 01010 }
{ 01100 }
{ 10100 }
{ 00001 }
{ 01010, 10100 }
{ 01010, 00001 }
{ 01100, 00001 }
{ 10100, 00001 }
{ 01010, 10100, 00001 }

实现这一目标的最佳算法是什么?

这个问题可以用图来重新表述,其中 S 的每个元素都是一个节点,兼容的元素由边连接。在这种情况下,问题变成了找到所有可能的节点集完全连接(即每对节点之间是否存在直接边)。

【问题讨论】:

  • 你想生成所有子集,还是简单地(没那么简单)对它们进行计数?
  • 我要生成所有子集。
  • 这与stackoverflow.com/questions/30893292/… 本质上是同一个问题(表述为位向量而不是集合,但算法相同)。
  • @rici,我不太明白你提到的问题。例如,它声明2个分区的交集是空集,然后作为例子,它使用{1,2,3}和{1,2},它们显然没有空交集。但是,我投票赞成你对那个问题的回答,这与我自己提出的算法非常相似。
  • @fabio:我认为问题中的示例很难阅读,因为它们是一起运行的;我添加了一些可能会有所帮助的新行。当我这样做时,我注意到我在评论中留下了指向有效解决方案的链接;值得注意的是,五年后链接仍然很好:ideone.com/6vaXaN

标签: algorithm set graph-algorithm combinatorics


【解决方案1】:

你可以使用这种方法

定义L 组如下 在i 组中,将所有具有位1 的节点放在i 等级中 所以问题是从每个组中选择one 或none。 显然每个组的元素不能超过one *如果某个节点有不止一位1,那么它会被重复计算,所以我们需要在最后除以1计数

所以结果计数如下: (Count(L_1)+1) * (Count(L_2)+1) *... * (Count(L_L)+1) / (countOfOne(element1) * ...* countOfOne(elementN)) 您应该忽略除法部分中的所有零 00..00 元素

【讨论】:

  • 对不起,我不明白。您如何确保第 1 组的一个元素与第 2 组的一个元素正交?
  • 例如,仅第一组的所有元素呢?另外,我不需要计算,我需要获取实际的集合。
【解决方案2】:

我解决了问题,分享解决方案可能会很有用。

首先我枚举集合中的元素。例如:

S = { 0: 01010, 1: 01100, 2: 10100, 3: 00001 }

现在任何子集都可以由索引集按升序定义。例如

{ 01010, 00001 } -> {0, 3}

我将 P 定义为一对(indices, bitmask),其中位掩码是通过按位或子集中的所有元素获得的。例如:

{ 01010, 00001 } -> ({0, 3}, 01011}

我将解 G 描述为 P 的向量。我将其初始化为所有仅包含一个元素的子集,这些元素肯定是解的一部分。

G = [ {{0}, 01010}, {{1}, 01100}, {{2}, 10100}, {{3}, 00001} ]

n 元素的每个兼容子集必须从与 n-1 元素添加单个元素的兼容子集中获得。这表明了伪代码中的算法:

设firstSol(n) 是一个函数,返回 G 中大小为 n 的第一个解的索引 设lastSol(n) 是一个函数,返回 G 中最后一个大小为 n 的解的索引 设 N 为 S 的大小

int n = 1;
int s;
do
    s = nSolutions(G) 
    for (i = firstSol(n); i <= lastSol(n); ++i)
       {vec, mask} = G[n];
       for (j = vec[n-1] + 1; j < N; ++j)
          if (mask & S[j] == 0)
             append to G: {{vec, j}, mask | S[j}}
while (s < nSolutions(G)) 

一旦没有找到新的解决方案,算法就会停止。

【讨论】:

    猜你喜欢
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    相关资源
    最近更新 更多