Algorithm 找到最佳点以切割一组间隔

Algorithm 找到最佳点以切割一组间隔,algorithm,optimization,time-complexity,scheduling,integer-programming,Algorithm,Optimization,Time Complexity,Scheduling,Integer Programming,给定实线上的一组区间和一些参数d>0。查找相邻点之间的间距小于或等于d的点序列,以使包含任何点的间隔数最小化。 为了防止琐碎的解决方案,我们要求序列中的第一个点在第一个间隔之前,最后一个点在最后一个间隔之后。间隔可以被认为是右开的 这个问题有名字吗?甚至可能是一个算法和复杂度界限 一些背景: 这是由拓扑数据分析中的一个问题引起的,但它似乎太笼统了,对于其他主题可能会很有趣,例如任务调度(假设工厂每年至少关闭一次,并希望将维护造成的任务数量降至最低……) 我们考虑了和,但是d参数不太合适。我们也在

给定实线上的一组区间和一些参数d>0。查找相邻点之间的间距小于或等于d的点序列,以使包含任何点的间隔数最小化。 为了防止琐碎的解决方案,我们要求序列中的第一个点在第一个间隔之前,最后一个点在最后一个间隔之后。间隔可以被认为是右开的

这个问题有名字吗?甚至可能是一个算法和复杂度界限

一些背景: 这是由拓扑数据分析中的一个问题引起的,但它似乎太笼统了,对于其他主题可能会很有趣,例如任务调度(假设工厂每年至少关闭一次,并希望将维护造成的任务数量降至最低……) 我们考虑了和,但是d参数不太合适。我们也在n^2和n*logn时间内实现了近似贪婪解,但它们可能会遇到非常糟糕的局部最优解

给我看张照片

我用线画间隔。下图显示了7个间隔。d是这样的,你必须至少每四个字符剪切一次。在图的底部,您可以看到图的两个解决方案(用x和y标记)。x穿过顶部的四个间隔,而y穿过底部的三个间隔。y是最优的

 ——— ———
 ——— ———
   ———
   ———
   ———
x x   x x
y   y   y
给我看一些代码: 在下面的代码片段中,我们应该如何定义
fun

interval=[(0,1)、(0.5,1.5)、(0.5,1.5)]
d=1.1
乐趣(间歇,d)
>>>[-0.55,0.45,1.55]#或接近它的东西
在这个小例子中,最优解将缩短第一个间隔,而不是第二个和第三个间隔。显然,该算法也应该适用于更复杂的示例

更严格的测试可以是以下内容:给定[0,100]上间隔开始时间的均匀分布和[0,d]上长度的均匀分布,可以通过规则网格[0,d,2d,3d,…]计算出略低于0.5*n的预期切割次数。最佳解决方案应该更好:

n=10000
δ=1
开始=np.随机.均匀(低=0,高=99,大小=n)
长度=np.随机.均匀(低=0,高=1,尺寸=n)
rand_interval=np.array([start,start+length]).T
规则网格=np.arange(0,101,1)
最佳网格=乐趣(随机间隔)
#这将计算被其中一个点切割的间隔数
def切割(间隔、网格):
箱子=np。数字化(间隔、网格)
返回和(箱子[:,0]!=箱子[:,1])
切割(随机间隔、规则网格)
>>>4987#预计略低于0.5*n

assert cuts(rand\u interval,optimal\u grid)您可以通过动态规划来优化此问题,方法是维护一个数组
S[k]
,其中
S[k]
是最佳解决方案(覆盖最大的空间量),而
k
区间中有一个点。然后,您可以重复删除最低的
S[k]
,以所有可能的方式扩展它(将自己限制在间隔的相关端点加上
S[k]
+delta中的最后一点),并使用这些新的可能解决方案更新
S
。 当表中最低的
S[k]
覆盖整个范围时,您就完成了

使用pip中的
intervaltree
的Python 3解决方案:

从intervaltree导入间隔,intervaltree
def最佳_点(间隔,d,ε=1e-9):
间隔=[间隔(lr[0],lr[1]),用于间隔中的lr]
树=间隔树(间隔)
开始=分钟(iv.每隔一段时间开始iv)
停止=最大值(间隔中的iv结束)
#含有一个点的k区间的最佳部分解。
#我们还将包含这些点的间隔存储为一个集合。
sols={0:([start],set())}
尽管如此:
最低k=min(sols.keys())
s、 包含=sols.pop(最低值)
#打印(最低k,s[-1]),用于跟踪缓慢情况下的进度。
如果s[-1]>=停止:
返回s
相关间隔=树[s[-1]:s[-1]+d]
相关_点=[iv.begin-相关_间隔内的ivε]
相关_点+=[iv.end+相关_间隔内iv的ε]
如果s[-1]sols[新的k][0][1]:
sols[new_k]=(新的,包含新的)

如果迭代的范围和精度可行,我们可以首先合并并计算间隔。比如说,

[(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)
,其中最右边的第二个点距离当前
n
的距离小于
d
,从而使新的中间点
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).

由于您的工厂类比,我假设间隔不重叠,因此我删除了我的答案。我相信添加一个图表将提高对问题的理解。添加了一个简单的ASCII artsy图表。希望这会有帮助。这看起来很有希望。尽管如此,有些事情并不像我期望的那样,请检查以下ex