给出实线上的一组间隔,并且某些参数d>0。找到一个点序列,其相邻点之间的间隙小于或等于d,以使包含任何点的间隔数最小化。 为了避免琐碎的解,我们要求序列中的第一个点在第一个间隔之前,而最后一个点在最后一个间隔之后。间隔可以认为是右开。
这个问题有名字吗?也许甚至是算法和复杂性的界限?
某些背景: 这是由拓扑数据分析中的一个问题所激发的,但是它看起来如此笼统,以至于对于其他主题(例如,计算机应用)可能会很有趣。任务计划(假设工厂每年至少要关闭一次,并且希望最大程度地减少维护带来的任务数量...) 我们曾考虑过integer programming和minimum cuts,但d参数不太合适。我们还在n ^ 2和n * logn的时间内实现了近似贪婪的解决方案,但它们可能会遇到非常糟糕的局部最优解。
给我看照片
我按行绘制间隔。下图显示了7个间隔。 d使得您必须至少每隔四个字符剪切一次。在图的底部,您可以看到图的两个解决方案(分别用x和y标记)。 x穿过顶部的四个间隔,而y穿过底部的三个间隔。 y是最优的。
——— ———
——— ———
———
———
———
x x x x
y y y
给我看一些代码:
在以下代码段中,我们应该如何定义fun
?
intervals = [(0, 1), (0.5, 1.5), (0.5, 1.5)]
d = 1.1
fun(intervals, d)
>>> [-0.55, 0.45, 1.55] # Or something close to it
在这个小例子中,最佳解决方案将减少第一个间隔,但不会减少第二个和第三个间隔。显然,该算法也应适用于更复杂的示例。
以下是更严格的测试:假设间隔开始时间在[0,100]上均匀分布,并且长度在[0,d]上均匀分布,则可以通过规则网格[0, d,2d,3d ..]略低于0.5 * n。最佳解决方案应该更好:
n = 10000
delta = 1
starts = np.random.uniform(low=0., high=99, size=n)
lengths = np.random.uniform(low=0., high=1, size=n)
rand_intervals = np.array([starts, starts + lengths]).T
regular_grid = np.arange(0, 101, 1)
optimal_grid = fun(rand_intervals)
# This computes the number of intervals being cut by one of the points
def cuts(intervals, grid):
bins = np.digitize(intervals, grid)
return sum(bins[:,0] != bins[:,1])
cuts(rand_intervals, regular_grid)
>>> 4987 # Expected to be slightly below 0.5*n
assert cuts(rand_intervals, optimal_grid) <= cuts(rand_intervals, regular_grid)
答案 0 :(得分:2)
您可以通过以下方式通过动态编程来最佳解决此问题:维护数组S[k]
,其中S[k]
是最佳解决方案(覆盖最大空间),同时在k
间隔中有一个点它。然后,您可以重复删除最低的S[k]
,以所有可能的方式扩展它(将自己限制为区间的相关端点以及S[k]
的最后一个点+增量),并用{这些新的可能的解决方案。
当表格中最低的S
覆盖整个范围时,您就完成了。
使用pip中的S[k]
的Python 3解决方案:
intervaltree
答案 1 :(得分:0)
如果范围和精度可以进行迭代,我们可以首先合并并计算间隔。例如,
[(0, 1), (0.5, 1.5), (0.5, 1.5)] ->
[(0, 0.5, 1), (0.5, 1, 3), (1, 1.5, 2)]
现在,让f(n, k)
代表最优解,其中k
指向数字行上的n
。然后:
f(n, k) = min(
num_intervals(n) + f(n - i, k - 1)
)
num_intervals(n) is known in O(1)
from a pointer in the merged interval list.
n-i is not every precision point up to n. Rather, it's
every point not more than d back that marks a change
from one merged interval to the next as we move it
back from our current pointer in the merged-interval
list.
要注意的一个问题是,对于任何最佳f(n, k)
,我们都需要存储最右点与上一个点之间的距离。这是为了避免加入f(n - i, k - 1)
到第二个最右边的点比我们当前的d
少n
的位置,从而使新的中间点n - i
变得多余并且无效这个解决方案。 (我不确定我是否已经彻底解决了这个问题。也许有人可以指出一些不对劲的问题。)
我们怎么知道k
足够高?鉴于最佳解决方案可能低于当前的k
,我们假设重复发生将阻止我们根据上段中的思想找到实例:
0.......8
——— ———
——— ———
———
———
———
x x x x
y y y
d = 4
merged list:
[(1, 3, 2), (3, 4, 5), (4, 5, 3), (5, 6, 5), (6, 8, 2)]
f(4, 2) = (3, 0) // (intersections, previous point)
f(8, 3) = (3, 4)
There are no valid solutions for f(8, 4) since the
break point we may consider between interval change
in the merged list is before the second-to-last
point in f(8, 3).