Algorithm 最大化覆盖率、最小化项目使用率的算法?
我有一个场景,你可以这样设想: 从宽100像素、高1000像素的图像开始。 除了该图像之外,还有一组该图像的裁剪部分。每个部分宽100像素,高100像素。节中包含的图像部分各不相同。例如,可能有一个从最顶端(像素0)开始,然后一个从垂直像素3开始,然后一个从垂直像素9开始,依此类推 我需要做的是找到一种方法来查看这些较小的图片集,并挑选出最小数量的部分,使我能够最大程度地覆盖原始图像 几点注意:Algorithm 最大化覆盖率、最小化项目使用率的算法?,algorithm,Algorithm,我有一个场景,你可以这样设想: 从宽100像素、高1000像素的图像开始。 除了该图像之外,还有一组该图像的裁剪部分。每个部分宽100像素,高100像素。节中包含的图像部分各不相同。例如,可能有一个从最顶端(像素0)开始,然后一个从垂直像素3开始,然后一个从垂直像素9开始,依此类推 我需要做的是找到一种方法来查看这些较小的图片集,并挑选出最小数量的部分,使我能够最大程度地覆盖原始图像 几点注意: 图像的内容其实并不重要。它真正匹配了重要的坐标 重建图像时,图像中永远不会有间隙,但可能没有足够的碎
O(N)
时间内工作,否则O(N*max\u重叠)
。诀窍是“向前和向后”
这假设您将添加一个额外的正方形,即使覆盖率为额外的0.0001%,即“在每个点上,如果可以用正方形覆盖,则必须用正方形覆盖”。不过,您可以修改此算法以适当权衡
这进一步假设,并非所有的正方形都在一个点上彼此重叠(它们有些分散,但仍可能重叠);否则可能需要很长时间
还要注意的是,每当你有一个未用正方形填充的断点时,你可以将问题分成子问题。这一确切的问题包含在下面 贪婪型算法将以最佳方式解决您的问题 假设您希望首先覆盖尽可能多的非不相交区域,然后使用给定第一个约束的最少数量的部分,那么此算法将在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)]
对不起,我不明白为什么这个问题是NP难的 一般的想法是,您将通过选择“最佳”部分来迭代删除图像的底部部分,即
- 覆盖图像底部的最大部分
- 如果你找不到一个(因为没有一个部分覆盖最后一行像素),只需要最靠近底部的一个
- 冲洗并重复
我认为设置固定高度部分(100像素)会消除NP硬度。@Tim,裁剪的部分是重叠的还是唯一的?它们肯定会重叠。事实上,会有很多重叠,这就是为什么尽量减少使用的#部分是重要的。@Tim,酷,那么如果你采取贪婪的方法,使用重叠量最小的裁剪部分可以吗?这听起来非常类似于集合覆盖问题(),这是NP难问题。当然,它的结构比一般情况要复杂得多,因此如果存在一个有效的解决方案,我也不会感到太惊讶。另外,您对有界问题大小感兴趣,因此渐近性能可能不是问题。但要记住一点。找到一个减量是很有趣的…@Tim,大约有多少个100x100的截面是典型的?不幸的是,我不能相信这种说法能以最佳方式解决问题。这是一个NP难问题,即使我们只使用固定大小的正方形,也可能仍然是一个困难的问题。这并不是说不应该使用贪婪的方法或者不会产生好的结果。但不幸的是,声称它将以最佳方式解决问题是行不通的。例如,如前所述,这种特殊的贪婪算法将在以下情况下选取所有矩形:
[A{](B}C)
,而不仅仅是A和C.3SAT所需的最小值是NP完全的。2 SAT是3SAT的子集。我可以给你一个2SAT的快速优化算法。我认为[(0,3)、(1,4)、(3,5)]示例与您的测试用例同构。我的psuedo代码有缺陷,我修复了它,它可以在您的测试用例上运行。这与我最终实现它的方式非常吻合
#!/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)]