【问题标题】:Find if any set is covered by member sets查找是否有任何集合被成员集覆盖
【发布时间】:2013-06-02 01:28:06
【问题描述】:

[如果这涉及到已知问题,请告诉我]

我有 n 套不同尺寸的。集合中的每个元素都是唯一的。每个元素最多可以出现在两个不同的集合中。

我想对这些集合执行操作,但要避免重复或丢失任何元素。 问题:找出所有这 n 个集合中的哪些应该被删除,因为它们被其他集合所覆盖。

例如[a,b,c]; [一个]; [乙]。删除 [a], [b] 因为两者都被第一个覆盖。

例如[a,b,c]; [一个]; [b]; [光盘]。删除 [a,b,c] 因为所有三个元素都被剩余的集合覆盖。 注意:这里的 [a],[b] 单独不是有效的答案,因为 'c' 被复制。同样,[a],[b],[c,d] 不是有效答案,因为如果删除 'd' 将丢失。

【问题讨论】:

  • 预期的套数是多少?集合中的最大元素数?不同元素的最大数量?
  • 请注意,一般情况下可能没有解决方案。例如,对于集合 {a,b}、{b,c}、{a,c},没有避免元素重复的 {a,b,c} 覆盖。
  • 嗯,在我的场景中,我预计大约 10 组;一个集合中的元素数可能是 1000s(最大元素数相同)。但是我从算法的角度提出了这个问题。 {a,b}{b,c}{c,a} 有两个以上的 a,b,c 副本。
  • 对于集合 {a,b}{b,c}{c,a}abc 中的每一个都正好在两组中。这如何违反您的条件?
  • [a,b,c,d], [a,e], [b,c], [d,e] 的结果是什么?

标签: algorithm set


【解决方案1】:

我认为这是Exact Cover problem。最后一个约束——每个元素最多分为两组——在我看来并没有从根本上改变问题(尽管我很容易在这方面犯错)。维基百科网页包含各种算法方法的很好的总结。选择的算法似乎是Dancing Links

【讨论】:

  • 由于一个数字只能出现一次或两次,这比精确覆盖要容易。
【解决方案2】:

我认为这是一个2-sat problem 的情况,可以使用基于Tarjan's algorithmmethod 在线性时间内解决。

  1. 为每个集合 i 创建一个变量 Ai。当且仅当要包含集合 i 时,Ai 才为真。
  2. 为单个集合中出现的每个元素添加 Ai=1 的子句
  3. 对于出现在 2 个集合 i 和 j 中的每个元素,添加子句 (Ai && ~Aj) || (~Ai && Aj)。这些子句意味着 Ai 和 Aj 中的一个必须出现。

您现在可以使用标准的 2-sat 算法来解决这个问题,以确定这是不可能实现的,或者如果可能的话,是一个令人满意的任务。

对于具有 V 个集合和 N 个元素的情况,您将有 V 个变量和多达 2N 个子句,因此 Tarjan 的算法将具有 O(V+2N) 的复杂度。

【讨论】:

  • 我认为这是正确的,基本上等同于我的答案。我怀疑这可能比我的开销更少,因此运行得更快。
【解决方案3】:

由于一个集合中的一个元素最多只能出现在两个集合中,那么集合之间就有相当直接的联系,可以用图表来表示,两个例子如下所示。一个例子用红线表示边缘,另一个用黑线表示边缘。

以上说明集合可以分为三组。

  1. 设置所有元素出现两次的位置。这些集合可能会被移除和/或包含这些元素的集合可能会被移除。
  2. 设置一个或多个元素出现两次的位置。出现两次的元素可能会链接到可以删除的集合。
  3. 设置没有元素出现两次。这些集合可以忽略。

目前还不清楚如果所有集合都在第 1 组或第 3 组中会发生什么。但是似乎有一个相当简单的标准可以快速删除集合,伪代码如下所示:

for each set in group2:
    for each element that appears twice in that set:
        if the other set that contains that element is in group1:
            remove the other set

然后,性能与元素数量成线性关系。

【讨论】:

  • 感谢大家提供的各种解决方案!
  • 实现它们并看看哪个效果最好可能不是一个坏主意。
【解决方案4】:

我试图找出要包含而不是删除的集合。像这样?

(1) 元素列表及其所在集合的索引
(2) 使用具有仅出现在其中的元素的集合的索引来填充答案列表
(3) 梳理 (1) 中的映射,如果一个元素的 set-index 不在答案列表中,则将该元素所在的最小集合的索引添加到答案中。

Haskell 代码:

import Data.List (nub, minimumBy, intersect)

sets = [["a","b","c","e"],["a","b","d"],["a","c","e"]]
lengths = map length sets

--List elements and the indexes of sets they are in

mapped = foldr map [] (nub . concat $ sets) where
  map a b = comb (a,[]) sets 0 : b
  comb result   []     _     = result
  comb (a,list) (x:xs) index | elem a x  = comb (a,index:list) xs (index + 1)
                             | otherwise = comb (a,list) xs (index + 1)

--List indexes of sets that have elements that appear only in them

haveUnique = map (head . snd)
           . filter (\(element,list) -> null . drop 1 $ list) 
           $ mapped

--Comb the map and if an element's set-index is not in the answer list,
--add to the answer the index of the smallest set that element is in.

answer = foldr comb haveUnique mapped where
  comb (a,list) b 
    | not . null . intersect list $ b = b
    | otherwise                       = 
        minimumBy (\setIndexA setIndexB -> 
                    compare (lengths!!setIndexA) (lengths!!setIndexB)) list : b

输出:

*Main> sets
[["a","b","c","e"],["a","b","d"],["a","c","e"]]

*Main> mapped
[("a",[2,1,0]),("b",[1,0]),("c",[2,0]),("e",[2,0]),("d",[1])]

*Main> haveUnique
[1]

*Main> answer
[2,1]

【讨论】:

    猜你喜欢
    • 2020-05-13
    • 1970-01-01
    • 2016-07-04
    • 2023-03-31
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多