寻找最佳点以减少间隔

时间:2019-07-29 09:23:16

标签: algorithm optimization time-complexity scheduling integer-programming

给出实线上的一组间隔,并且某些参数d>0。找到一个点序列,其相邻点之间的间隙小于或等于d,以使包含任何点的间隔数最小化。 为了避免琐碎的解,我们要求序列中的第一个点在第一个间隔之前,而最后一个点在最后一个间隔之后。间隔可以认为是右开。

这个问题有名字吗?也许甚至是算法和复杂性的界限?

某些背景: 这是由拓扑数据分析中的一个问题所激发的,但是它看起来如此笼统,以至于对于其他主题(例如,计算机应用)可能会很有趣。任务计划(假设工厂每年至少要关闭一次,并且希望最大程度地减少维护带来的任务数量...) 我们曾考虑过integer programmingminimum 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)

2 个答案:

答案 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)到第二个最右边的点比我们当前的dn的位置,从而使新的中间点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).