在列表中合并非交叉集合以最终得到密集的集合的好方法是什么?

时间:2013-05-24 09:41:04

标签: python algorithm

我目前通过使用一种贪婪算法,通过从最大集到最小集迭代集来实现这一点。如果我更关心找到最佳解决方案而不是效率,那么选择什么样的算法呢?

详细说明:
1)每组具有预定范围
2)我的目标是最终得到大量密集的集合,而不是减少集合的总数。

示例:假设范围为8

这些集可能是:[1,5,7][2,6][3,4,5][1,2][4][1]
一个好的结果是[1,5,7,2,6,4][3,4,5,1,2][1]

3 个答案:

答案 0 :(得分:1)

这是一个非常复杂的问题。很可能使用更复杂的图形算法,这可以用比我想象的更有效的方式解决,但这就是我所拥有的。生成所有解决方案的速度相当慢,但由于它是一个生成器,因此根据具体情况,从第一个 n 中选择解决方案可能是一个选项。

它没有解决哪个解决方案最好的问题,它只是生成所有可能的解决方案。此外,您没有明确说明“最佳”密集包装是什么。在原始示例中(没有[4]),解决方案12567-12345-1是否优于123456-157-12?如果是这样,为什么?说到长度,解决方案1将是(5,5,1),而解决方案2将是(6,2,3)。哪个更好?

input = map(set, [ [1,5,7], [2,6], [3,4,5], [1,2], [4], [1] ])

def eachCombination(input):
  if input:
    for combination, rest in eachCombination(input[1:]):
      yield combination, input[0:1] + rest
      if not (input[0] & combination):  # fits?
        yield input[0] | combination, rest
  else:
    yield set(), []

def eachPacked(input):
  for combination, rest in eachCombination(input):
    for restPart in rest:
      if not (combination & restPart):  # not densely packed?
        break
    else:
      yield combination, rest

def eachSolution(input):
  for packed, rest in eachPacked(input):
    if rest:
      for subsolution in eachSolution(rest):
        yield [ packed ] + subsolution
    else:
      yield [ packed ]

for solution in eachSolution(input):
  print '   '.join('-'.join('%d' % n for n in set) for set in solution)

这将打印

1-2-3-4-5   1-2-4-5-6-7   1
1-2-3-4-5   1-2-4-6   1-5-7
1-2-4-5-6-7   1-2-3-4-5   1
1-2-4-5-6-7   1-3-4-5   1-2
1-2-4   1-2-5-6-7   1-3-4-5
1-2-4   1-2-3-4-5-6   1-5-7
1-2-3-4-5-6   1-4-5-7   1-2
1-2-3-4-5-6   1-2-4   1-5-7
1-2-4-6   1-5-7   1-2-3-4-5
1-2-4-6   1-2-3-4-5   1-5-7

答案 1 :(得分:1)

这是一个近似值,使用动态编程:

http://ideone.com/SI1wEs

from operator import itemgetter

def find_maximum_set(sets):
    results = []
    for si,s in enumerate(sets):
        sn = len(s)
        new_set = set(s) # if nothing else works, add the set by itself
        new_len = sn
        new_is = [si]

        # try to combine it with all the previous results, picking the one that
        # would produce the largest union
        for rn,ris,r in results:
            if r.isdisjoint(s):
                rs = r.union(s)
                if rn+sn > new_len:
                    new_set = rs
                    new_len = rn+sn
                    new_is = ris + [si]

        # add the new set to the result collection
        results.append((new_len,new_is,new_set))

    # return the largest result
    return max(results, key=itemgetter(0))

def find_all_maximum_sets(sets):
    sets = list(sets)
    result = []
    while len(sets) > 0:
        _, indexes, largest = find_maximum_set(sets)
        result.append(largest)
        sets = [s for i,s in enumerate(sets) if i not in indexes]
    return result

示例:

>>> find_all_maximum_sets([[1,5,7], [2,6], [3,4,5], [1,2] , [4], [1]])
[set([1, 2, 4, 5, 6, 7]), set([1, 2, 3, 4, 5]), set([1])]

答案 2 :(得分:0)

我不确定它是否会提供最佳解决方案,但只是反复合并两个最大的非重叠集合不起作用?