问题描述
|
我有一个可以通过这种方式设想的方案:
从100像素宽乘1000像素高的图像开始。
除了该图像之外,您还具有该图像的一组裁剪部分。每个部分的宽度为100像素,高度为100像素。该部分中包含的图像部分有所不同。例如,您可能有一个从最顶部开始(像素0),然后有一个从垂直像素3开始,然后有一个从垂直像素9开始,依此类推。
我需要做的是找到一种方法来查看那些较小的图片集,并选择最少的部分,从而使我对原始图像的覆盖率最高。
一些注意事项:
图像的内容并不重要。它确实与重要的坐标相匹配。
重建时,图像中永远不会有间隙,但是可能没有足够的碎片到达底部。
这些部分之间会有很多重叠。实际上,在某些情况下,两个部分之间只有一个或两个像素(垂直)差异。
有人可以在这里指出正确的方向吗?我可以做这种蛮力……但我认为有更好的方法。
解决方法
很抱歉,但是我看不到为什么这个问题很难解决。
通常的想法是,您可以通过选择“最佳”部分来迭代地删除图像的底部,即
覆盖图像底部的最大部分
如果找不到某个像素(因为没有部分覆盖最后一行像素),请选择最接近像素的像素。
冲洗并重复
首先对部分进行排序。您会得到类似(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硬度。
, 我认为这是http://en.wikipedia.org/wiki/Maximum_coverage_problem-集合的元素是像素(您可以编写代码以使其不逐像素处理事物)。
因为是100x1000,所以问题不再是NP难题,甚至在P中也是如此。贪婪的方法将不起作用,但是存在如下的动态编程解决方案,如果充分扩展,则该解决方案大约在ѭ0时间内起作用,否则ѭ1。诀窍是“向前和向后”。
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%的覆盖率,也要添加一个额外的正方形,即\“在每个点上,如果有可能覆盖正方形,则必须覆盖正方形\”。您可以修改此算法,但要适当权衡。
这进一步假设并非几乎所有正方形都在单个点处彼此重叠(它们有些散开,但仍可能重叠)。否则可能会花费很长时间。
另请注意,每当您有一个没有用正方形填补的休息时,就可以将问题分为多个子问题。
, 这个确切的问题由算法专家解决。
贪婪的扫描线样式算法算法将最佳地解决您的问题。
假设您要首先覆盖尽可能多的不相交区域,然后在给定第一个约束的情况下使用最少的数字部分,那么该算法将在O(n ^ 2)时间内为您解决问题。
基本思想是按从上到下的顺序进行,仅当您“裸体”时才选择一个部分,也就是说,没有涵盖给定的部分。当您被迫参加一个部分时,将最能覆盖您的部分放在“未来”中。此实现为O(n ^ 2),但您可以通过更好地管理Cands使其变为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,5)]
assert cover_max_segment_min([(0,5),4)]) == \\
[(0,3)]) == [(0,3)]
assert cover_max_segment_min([]) == []
assert cover_max_segment_min([(-10,10),2),5)]) == [(-10,10)]
assert cover_max_segment_min([(1,(2,4)]) == \\
[(1,4)]
assert cover_max_segment_min([(1,3)]) == \\
[(1,4)]