确定无冲突集?

时间:2013-04-16 22:56:32

标签: algorithm design-patterns

假设你有一堆集合,而每个集合都有几个子集。

Set1 = {(香蕉,菠萝,橙子),(苹果,羽衣甘蓝,黄瓜),(洋葱,大蒜)}

Set2 = {(香蕉,黄瓜,大蒜),(牛油果,番茄)}

...

SetN = {...}

现在的目标是从每个集合中选择一个子集,而每个子集必须与任何其他所选子集无冲突。对于这个玩具大小的例子,一个可能的解决方案是选择(香蕉,菠萝,橙色)(来自Set1)和(鳄梨,番茄)(来自Set2)。

如果会选择Set1和Set2的第一个子集,则会发生冲突,因为香蕉将包含在两个子集中(这是不可能的,因为它只存在一次)。

即使有很多算法,我也无法选择合适的算法。我在某种程度上陷入困境,并希望得到针对以下问题的答案:

1)如何找到合适的算法并以可以通过算法处理的方式表示这个问题?

2)这个玩具尺寸示例的可能解决方案可能如何(任何语言都很好,我只是想得到这个想法)。

Edit1:我也在考虑模拟退火(返回一个可能的解决方案)。这可能是有意义的,以最小化例如选择集合的总成本。但是,我无法弄清楚如何进行适当的问题描述,将“冲突”考虑在内。

2 个答案:

答案 0 :(得分:8)

此问题可以表述为generalized exact cover problem

为每组设置(Set1,Set2等)创建一个新原子,并将输入转换为如下所示的实例:

{Set1, banana, pineapple, orange}
{Set1, apple, kale, cucumber}
{Set1, onion, garlic}
{Set2, banana, cucumber, garlic}
{Set2, avocado, tomato}
...

使Set*个原子成为主要原因(仅覆盖一次),其他原子成为次要原则(最多覆盖一次)。然后你可以用Knuth算法X的推广来解决它。

答案 1 :(得分:4)

查看集合列表,我有一个有多个入口的迷宫图像。该任务类似于从顶部到底部跟踪没有子集交叉的路径。 Haskell中的示例选择所有入口,并尝试每条路径,返回成功的路径。

我对代码如何工作的理解(算法):

对于第一组中的每个子集,选择下一组中的每个子集,其中该子集与累积结果中的每个子集的交集为空。如果没有符合条件的子集,则打破循环的应变。如果没有可供选择的集合,则返回该结果。为所有选择的子集(以及相应的累积结果)递归调用函数。

import Data.List (intersect)
import Control.Monad (guard)

sets = [[["banana", "pineapple", "orange"], ["apple", "kale", "cucumber"], ["onion", "garlic"]]
       ,[["banana", "cucumber", "garlic"], ["avocado", "tomato"]]]

solve sets = solve' sets [] where
  solve' []         result = [result]
  solve' (set:rest) result = do
    subset <- set
    guard (all null (map (intersect subset) result))
    solve' rest (result ++ [subset])

输出:

*Main> solve sets
[[["banana","pineapple","orange"],["avocado","tomato"]]
,[["apple","kale","cucumber"],["avocado","tomato"]]
,[["onion","garlic"],["avocado","tomato"]]]