找到满足谓词的所有可能子集

时间:2020-12-20 05:05:35

标签: algorithm set graph-algorithm combinatorics

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

构成

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

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

如果 S 的所有元素的成对按位 AND 为零,则 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 的每个元素都是一个节点,兼容元素通过边连接。在这种情况下,问题就变成了找到所有可能完全连接的节点集(即每对节点之间是否存在直接边)。

2 个答案:

答案 0 :(得分:0)

你可以使用这种方法

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

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

答案 1 :(得分:0)

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

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

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)) 

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