问题:我有一个元组列表,如[(10,20),(20,30),(22,24),(26,30),(10,28)]我需要找到一个元组子列表,其最小重叠次数覆盖10,30(最大值和最小值)
我对如何处理这个问题有一些想法,但我想知道是否有人可以提出任何解决方案。
答案 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>
]