问题 选择涵盖最多单词的字母? [关闭]


给定一个单词列表和一个最多有P个字母的字母表,我们如何选择涵盖最多单词的最佳字母?

例如:给定单词“aaaaaa”“bb”“bb”,其中P = 1,最佳字母表是“b”,因为“b”包括两个单词。

另一个例子:给出单词“abmm”“abaa”“mnab”“bbcc”“mnnn”,其中P = 4,最佳字母表是“abmn”,因为它覆盖了5个单词中的4个。

有没有已知的算法,或者有人建议解决这个问题的算法?


6020
2017-10-11 11:26


起源

P可以有多大?那里有多少个不同的字母(总共有几个字)? - kraskevich
我正在努力弄清楚究竟是怎么回事,但这并不是微不足道的。我建议虽然看看背包问题的动态编程伪多项式解决方案,但我打算尝试这种方式。 - Nir Friedman
这个问题的旧版本怎么能收到9个downvotes,这个明显的第二次尝试收到10个upvotes? - Marco13


答案:


从CLIQUE(它是一种最密集的k-sub(超)图问题)减少这个问题是NP难的。给定一个图形,用不同的字母标记其顶点,并为每个边缘创建一个两个字母的单词。当且仅当我们能够覆盖k选择2个单词和k个字母时,才存在k-clique。

CLIQUE的算法情况是 严峻 (在合理的假设下,运行时间必须是n ^ Theta(k)),所以我不确定除了蛮力与原始之外还要推荐什么 位数组


6
2017-10-11 15:22



很好的减少,永远不会想到尝试CLIQUE!我在3SAT上挣扎,取得了进步,但它又大又丑...... - j_random_hacker


我还不确定这是否正确,但希望它至少接近。我们考虑动态编程解决方案。枚举单词1到N,我们的字母表1到P中的字母。我们希望能够根据所有子解决方案求解(n,p)。我们考虑几个案例。

最简单的情况是第n个单词已经在(n-1,p)的解决方案中给出的字典中。然后我们将自己算作幸运,用一个词覆盖,并保持字典不变(ddictionary指的是这里的一些字母子集)。

相反,假设第n个单词不在(n-1,p)给出的字典中。然后字典求解(n-1,p)是(n,p)的字典,或者第n个字在解决方案中。因此,我们寻找明确涉及第n个单词的解决方案。因此,我们将第n个单词中的所有字母添加到我们正在考虑的字典中。我们现在搜索表格(n-1,i)的所有先前的子集,其中i是p-1或更小。我们正在寻找i的最大值,使得| d(n-1,i)U d(n)| <= p。其中d(n-1,i)表示与该解决方案相关联的字典,而d(n)仅表示与第n个单词的所有字母相关联的字典。用简单的英语,我们使用我们的子解决方案来找到具有较小p值的最佳解决方案,这允许我们适应新单词。一旦我们找到了i的值,我们就会结合我们测量的大小的字典。如果该集合的幅度仍然不是p,我们重复前面描述的过程。当我们创建一个大小为p的字典,用这种技术覆盖第n个单词(或通过所有先前的解决方案迭代),我们计算其覆盖范围并将其与我们通过简单地使用来自(n-1, p),我们选择更好。如果这是一个平局,我们选择两者。

我不完全相信这个解决方案的正确性,但我认为这可能是正确的。思考?


2
2017-10-11 13:46



我没有完全遵循你的第3段的部分,但我看到的一个难点是可能有许多不同的词典对某些(i <= n,j <= P)解决方案是最佳的,我认为它们都需要存储用于第一种情况(当第n个字已经在最佳地解决(n-1,P)的字典中时)被可靠地检测。 - j_random_hacker
我同意,但存储多个词典并不困难。我认为更大的担忧是它在某些情况下可能会巧妙地失败。解决方案是在背包问题之后建模的,但是这里背包的不同容量是独立的,而字典的联合可能具有更大,更多或更小的覆盖范围,两个字典的覆盖范围的总和(我认为更大)案件造成的问题最多)。它可能仍然有用;我认为值得张贴作为一个不错的开始。它没有完全回答这个问题所以如果愿意我可以把它拿下来。 - Nir Friedman


我这样做:

  1. 使用输入词创建一个数据结构,将字母(字符串)列表映射到它们覆盖的单词数。您可以通过提取构成单词的唯一字母,对它们进行排序并将结果用作哈希映射键来完成此操作。
  2. 忽略任何密钥长于P的条目(不能用我们有限的字母表覆盖这些单词)。
  3. 对于所有剩余的entires,计算它们包含的条目列表(字母'ab'包含字母'b'和'a')。汇总这些条目所涵盖的单词数。
  4. 找到键数最多的条目。

1
2017-10-11 14:10





正如大卫在上面所展示的那样(有一个很好的证明!),这是NP难的,所以你不会在任何情况下得到完美的答案。

添加到其他答案的一种方法是将其表达为最大流量问题。

定义源节点S,汇聚节点D,每个字的节点以及每个字母的节点。

将S中的边添加到容量1的每个字中。

将每个单词的边添加到包含无限容量的字母。

将每个字母的边添加到容量x的D(我们将在片刻中定义x)。

然后求解该图的最小切割(通过使用从S到D的最大流算法)。字母的切边表示该字母未包含在解决方案中。

这可以被认为解决了我们每个单词获得1的奖励的问题,但是对于我们使用的每个新单词,它花费我们x。

然后,想法是改变x(例如通过二分法)以试图找到x的值,其中恰好切割k个字母边缘。如果您对此进行了管理,那么您将确定问题的确切解决方案。

这种方法相当有效,但它取决于您的输入数据是否能找到答案。对于某些例子(例如大卫的构造来寻找派系),你会发现当你改变x时,你会突然从少于k个字母跳到包括多个k个字母。但是,即使在这种情况下,您可能会发现它有助于为精确解中的最大字数提供一些下限和上限。


1
2017-10-11 16:08