最大化覆盖率,最小化物品使用量的算法?

问题描述

| 我有一个可以通过这种方式设想的方案: 从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)]
    

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...