假设你在[1,10 ^ 18]中有k <= 10 ^ 5个区间[a_i,b_i] \(其中一些可能重叠),你需要选择一组相互不相交的区间,以便它们的联合是最大的。不是最大数量的不相交间隔,但工会必须覆盖最多。
不能尝试所有可能的子集2 ^ k不可行。 通过a_i(区间覆盖算法)排序的贪婪方法和按b_i排序(最大不相交区间数算法)没有工作 无法确定是否存在动态程序解决方案。 给定输入的大小,我认为解决方案应该是O(k log k)或O(k)
实例 1. [1,4],[3,5],[5,9],[7,18] Sol [3,5] u [7,18]
[1,2],[2,6],[3,4],[5,7] Sol [1,2] u [3,4] u [5,7]
[2,30],[25,39],[30,40] Sol [2,30]
答案 0 :(得分:2)
问题可以通过O(k log(k))
来解决。
首先按照上限(b_i
s)对间隔进行排序。让I(1), I(2), ..., I(k)
成为已排序间隔的列表。也就是说,
b_1 <= b_2 <= ... <= b_k
按w(i)
表示间隔I(i)
的长度。也就是说,
w(i) = b_i - a_i
由f(i)
表示最后一个间隔为I(i)
的最佳解决方案的总长度。也就是说,对应于f(i)
的解是一组:
I(i)
b_i
现在我们要计算f(1), f(2), ..., f(k)
并返回它们的最大值。显然,最优解对应于f(i)
之一,因此最大f(i)
是最优解。
要计算每个f(i)
,我们使用动态编程。我们依靠以下递归关系来做到这一点:
f(i) = w(i) + max{f(j) | b_j < a_i}
我将使用您的第一个输入示例演示计算:
I(1)=[1, 4], w(1)=3
I(2)=[3, 5], w(2)=2
I(3)=[5, 9], w(3)=4
I(4)=[7, 18], w(4)=11
我们为f(i)
计算i=1, 2, 3, 4
:
f(1) = w(1) + max{None} = 3
f(1) intervals: {I(1)}
f(2) = w(2) + max{None} = 2
f(2) intervals: {I(2)}
f(3) = w(3) + max{f(1)} = 4 + 1 = 5
f(3) intervals = {I(1), I(3)}
f(4) = w(4) + max{f(1), f(2)} = 11 + f(1) = 11 + 3 = 14
f(4) intervals = {I(1), I(4)}
最大f(i)
为f(4)
,对应于最佳解决方案{I(1), I(4)}
的间隔集。
答案 1 :(得分:0)
似乎有 O(k * log(k))解决方案。它可以通过分段树数据结构来实现。
我们可能首先填充一些 endPos 段结尾数组,然后对其进行排序。记住对应 endPos 索引的每个细分。为此,让 endPosIdx 成为 endPosIdx j 将在 endPos 中存储索引的数组 j - 第一段结束。
接下来我们将介绍一个分段树。它将处理以下请求:
1. getMax(i)
- 获取[0, i]
范围内的最大值
2. update(i, value)
- 使用i
更新value
位置的最大值
i 是 endPos 数组中的索引。如果 endPos i 之后非段的结束,我们会询问 getMax(i)我们可以获得的最大保障。调用更新(i,值)我们说现在存在一个长值的封面,以 endPos i 结尾
按起始位置 a j 按递增顺序对所有细分进行排序。按顺序处理它们。如果我们肯定会在结果集中获取当前段,那么要点是找到最大的覆盖。当前封面将等于当前段的长度与在当前之前结束的段的最大封面之和。设 j 为当前段的索引(它们按起始位置排序)。设 i 然后是 endPos i ≤a j ( i >的最大索引可以通过二进制搜索从 j 找到。然后我们可以找到
封面 j = length j + getMax(i)
接下来我们应该更新段树调用更新(endPosIdx j ,覆盖 j )并继续下一段。
处理完所有细分后,可以通过调用 getMax(size(endPos))找到解决方案。