我有一个你可以这样设想的场景:
从100像素宽,1000像素高的图像开始。 除了该图像,您还有一组该图像的裁剪部分。每个部分宽100像素,高100像素。该部分中包含的图像部分各不相同。例如,您可能有一个从最顶部(像素0)开始,然后一个在垂直像素3处,然后一个在垂直像素9处,依此类推。
我需要做的是找到一种方法来查看那些较小的图片集,并选出最小数量的部分,这些部分可以让我覆盖原始图像。
几点说明:
有人能指出我在正确的方向吗?我可以做这种蛮力......但我认为有更好的方法。
答案 0 :(得分:1)
我认为这是http://en.wikipedia.org/wiki/Maximum_coverage_problem - 集合的元素是像素(您可以编写代码,使其不像素一样处理事物)。
因为它是100x1000,所以问题不再是NP难,可能是P偶数。贪婪的方法不起作用,但存在如下动态编程解决方案,如果充分展开则大致在O(N)
时间工作,否则O(N * max_overlap_#)
。诀窍是“向前和向后”。
input:
[ ] to fill
[ (] ) { ([}) ] ( [) ]
return:
Result set of squares which maximize cover, secondarily
minimizing the size of the Result set if covered areas are equal
the score of the leftmost element is {area:100^2, num:1}
for each square S in order, left->right:
(Assuming you pick S in Result...)
let Candidates = {all squares which overlap S and are left of S}
+ {first non-overlapping square left of S}
for each candidate C:
let score(S) = score(C) + {area:new_area_covered_by_S, num:1}
pick candidate BestC which maximizes score(S)
draw a line between S and BestC
Take the square with the best score, and work your way backwards
along the chain of best-picks, returning only those squares.
这假设即使额外的0.0001%覆盖率也会增加一个额外的正方形,即“在每个点,如果可以用正方形覆盖,则必须用正方形覆盖”。您可以修改此算法,以便进行适当的权衡。
这进一步假设不是几乎所有的正方形在一个点上相互重叠的情况(它们有点展开但可能仍然重叠);否则可能需要很长时间。
另请注意,只要您有一个未被正方形填充的中断,您就可以将问题划分为子问题。
答案 1 :(得分:1)
我很抱歉,但我不明白为什么这个问题是NP难的。
一般的想法是,您可以通过选择“最佳”部分来删除图像的底部部分,即
首先对部分进行排序。你会得到像(0,1,3,10,...,988,999)这样的东西,其中0对应于从顶部像素开始的部分。 (与999相对应的只覆盖一行)
假设您的原始图像是100xN。最初,N = 1000。
设n是最能覆盖原始图像末尾的图像的索引:即n是该列表中的最小数,使得n + 100> = N.如果没有这样的数字,n就是最大的数字。
如果您的排序列表是(0,1,... 899,900,901,..,999),那么n = 900
如果您的排序列表是(0,1,... 899,905,910,..,999),那么n = 905
如果您的排序列表是(0,1,...,888,898,),那么n = 898
然后以N = n再次开始(你已经删除了原始图像底部的一部分)(当然,从排序列表中删除所有“> = n”的部分)
我认为设置固定高度的部分(100像素)会消除NP硬度。
答案 2 :(得分:0)
这个确切的问题由algorithmist涵盖。
贪婪的sweep line样式算法算法可以最佳地解决您的问题。
假设你想首先覆盖尽可能多的非不相交区域,其次使用给定第一个约束的最少数量的区域,那么这个算法将在O(n ^ 2)时间内为你解决问题。
基本的想法是从上到下按顺序排列,只在你“赤身裸体”时才拿一个部分,也就是说,没有覆盖给定的部分。当你被迫选择一个部分时,将最能覆盖你的部分带入“未来”。这个实现是O(n ^ 2),但你可以通过更好地管理cand来使它成为O(n log(n))。
#!/usr/bin/python
START_EVENT, END_EVENT = 0, 1 # handle starts before ends at same point
def max_future(cands):
return max(cands, key=lambda c: (c[1], c)[1])
def cover_max_segment_min(intervals):
events = []
for interval in intervals:
events.append((interval[0], START_EVENT, interval))
events.append((interval[1], END_EVENT, interval))
cands = []
outputs = []
alive = None
# Handle events by
# event time,
# starts before ends,
# longer endings before shorter endings
events.sort(key=lambda x: (x[0], x[1], -x[2][1]))
for k, event_type, interval in events:
if event_type == START_EVENT:
cands.append(interval)
if event_type == END_EVENT:
cands.remove(interval)
if interval is alive:
alive = None
if not alive and cands:
outputs.append(max_future(cands))
alive = outputs[-1]
return outputs
assert cover_max_segment_min([(0, 3), (1, 4), (3, 5)]) == \
[(0, 3), (3, 5)]
assert cover_max_segment_min([(0, 3), (3, 5), (1, 4)]) == \
[(0, 3), (3, 5)]
assert cover_max_segment_min([(0, 3)]) == [(0, 3)]
assert cover_max_segment_min([]) == []
assert cover_max_segment_min([(-10, 10), (1, 2), (3, 5)]) == [(-10, 10)]
assert cover_max_segment_min([(1, 2), (2, 3), (3, 4)]) == \
[(1, 2), (2, 3), (3, 4)]
assert cover_max_segment_min([(1, 4), (1, 2), (3, 3)]) == \
[(1, 4)]