查找具有最小重叠的元组子列表

时间:2015-04-03 14:45:53

标签: python

问题:我有一个元组列表,如[(10,20),(20,30),(22,24),(26,30),(10,28)]我需要找到一个元组子列表,其最小重叠次数覆盖10,30(最大值和最小值)

我对如何处理这个问题有一些想法,但我想知道是否有人可以提出任何解决方案。

1 个答案:

答案 0 :(得分:3)

有趣的问题:-) 解决这个问题并不容易。我不明白为什么它会被投票。

以下代码将检查所有子集,计算连续覆盖,重叠以及生成覆盖+重叠的元组列表。

最后它按重叠排序。因此,输出中的第一个元素应该是具有所需覆盖和最小重叠的元素。

from itertools import *
import operator

def allsubsets(l):
    for s in chain( *map(lambda r: combinations(l,r), xrange(1,len(l))) ):
        yield s


# only count tuples that make consecutive ranges
def mk_cover(acc, item):
    ((curlo, curhi), tuplist, ovl) = acc
    (newlo, newhi)                 = item
    if newlo<=curhi:
        # ok, the new item possibly extends the range
        if newhi>=curhi:
            overlap = curhi - newlo
        else:
            overlap = newhi - newlo
            newhi   = curhi
        return ((curlo, newhi), tuplist+[item], ovl+overlap)
    else:
        # it doesn't so return the old accumulator
        return acc

# return a function that will inspect lists-of-tuples
# to see if they cover the range lo -> hi. If they do,
# append the covering list and the overlap to an
# accumulator; a list of solutions found so far
def mk_finder(lo, hi):
    def overlapper(acc, tuples):
        # inspect the subset of tuples, wether they 
        # cover lo -> hi 
        # sort by start value
        tuples                    = list(sorted(tuples, key=operator.itemgetter(0)))
        ((covlo, covhi), tl, ovl) = reduce(mk_cover, tuples[1:], (tuples[0], [tuples[0]], 0))
        if covlo<=lo and covhi>=hi:
            acc.append( ((covlo, covhi), tl, ovl) )
        return acc
    return overlapper

使用以下输入:

inp = [  (10,20) , (20,30) , (22,24) , (26,30) , (10,28) ] 

# find all that cover 10,30
found = reduce(mk_finder(10, 30), allsubsets(inp), [])

# sort by overlap
found = [(tl, ovl) for (cov, tl, ovl) in sorted(found, key=operator.itemgetter(2))
print found

将此产量作为输出(是的,有许多子集覆盖范围10-30),表明组合(10,20)+(20,30)覆盖范围10-30,零重叠:

[([(10, 20), (20, 30)], 0),
 ([(10, 28), (26, 30)], 2),
 ([(10, 20), (20, 30), (22, 24)], 2),
 ([(10, 20), (20, 30), (26, 30)], 4),
 ([(10, 28), (22, 24), (26, 30)], 4),
 .... <snip> 
 ]