最大化覆盖范围的算法,最小化项目使用?

时间:2011-06-13 18:50:12

标签: algorithm

我有一个你可以这样设想的场景:

从100像素宽,1000像素高的图像开始。 除了该图像,您还有一组该图像的裁剪部分。每个部分宽100像素,高100像素。该部分中包含的图像部分各不相同。例如,您可能有一个从最顶部(像素0)开始,然后一个在垂直像素3处,然后一个在垂直像素9处,依此类推。

我需要做的是找到一种方法来查看那些较小的图片集,并选出最小数量的部分,这些部分可以让我覆盖原始图像。

几点说明:

  1. 图像的内容并不重要。它确实与重要的坐标相匹配。
  2. 重建时图像永远不会有间隙,但可能不足以到达底部。
  3. 各部门之间会有很多重叠。实际上,有些情况下两个部分之间只有一个或两个(垂直)差异。
  4. 有人能指出我在正确的方向吗?我可以做这种蛮力......但我认为有更好的方法。

3 个答案:

答案 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)]