【问题标题】:Max coverage disjoint intervals最大覆盖不相交间隔
【发布时间】:2017-08-02 18:53:31
【问题描述】:

假设您有 k

无法尝试所有可能的子集 2^k 不可行。 贪心方法按 a_i 排序(区间覆盖算法)和按 b_i 排序(最大不相交区间算法)不起作用 无法弄清楚是否有动态程序解决方案。 鉴于输入的大小,我认为解决方案应该是 O(k log k) 或 O(k)

示例 1. [1,4], [3,5], [5,9], [7, 18] 溶胶[3,5]u[7,18]

  1. [1,2], [2,6], [3,4], [5,7] 溶胶[1,2]u[3,4]u[5,7]

  2. [2,30], [25,39], [30,40] 索尔[2,30]

【问题讨论】:

  • 区间数是多少,a_i,b_i的值最多是多少?
  • 还请告诉您到目前为止您尝试了什么?
  • 提示:您可以按左边框对它们进行排序并计算dp[i] = 以i-th 段结尾的最大联合。如果您正确跟踪事件(或使用像段树这样的数据结构),则可以在O(k log k) 时间内完成。

标签: algorithm intervals greedy cover


【解决方案1】:

问题可以在O(k log(k))解决。

首先按区间的上限(b_is)对区间进行排序。让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)对应的解是一个集合:

  1. 包含区间I(i)
  2. 不包含任何上界高于b_i的区间
  3. 在满足 1+2 的(非重叠)区间集合中具有最大覆盖度

现在我们要计算f(1), f(2), ..., f(k) 并返回它们的最大值。显然,最优解对应于f(i)s 之一,因此最大的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

我们为i=1, 2, 3, 4 计算f(i)

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)},即最优解。

【讨论】:

  • 谢谢。我使用二进制搜索找到 max{f(j) | b_j
  • 一切正常,你的解释对我帮助很大,我已经编写了问题代码并被接受了我可以在这里提交代码,它可能对以后的其他人有帮助
  • 我认为,不是 O(k log(k)),找到 max{f(j) | b_j
  • @MukhtarBimurat: 是的,但是要知道你应该按什么顺序计算值 f(你考虑间隔的顺序),我不知道如果不对它们进行排序怎么办?
【解决方案2】:

似乎有一个 O(k * log(k)) 解决方案。可以通过段树数据结构来实现。

我们可能首先填充一些段结尾的 endPos 数组,然后对其进行排序。记住每个段对应的 endPos 索引。为此,让 endPosIdx 是这样的数组,endPosIdxj 将在 endPos 中存储一个索引,其中 j -第一个片段结束。

接下来我们将介绍一个段树。它将处理以下请求:
1. getMax(i) - 获取[0, i]范围内的最大值。
2. update(i, value) - 使用value 更新i-th 位置的最大值。
iendPos 数组中的索引。调用 getMax(i) 我们询问如果没有段在 endPosi 之后结束,我们可以达到的最大覆盖范围。调用 update(i, value) 我们说现在存在一个长度 valueendPosi 结尾的覆盖.

按起始位置aj对所有片段进行升序排序。按该顺序处理它们。如果我们肯定会在结果集中取当前段,那么要点是找到最大的覆盖。当前覆盖将等于当前段的长度和结束之前当前段的最大覆盖的总和。令 j 为当前段的索引(它们按起始位置排序)。令 iendPosi ≤ aj (i可以通过二分查找从 j 中找到)。然后我们可以找到

覆盖j = 长度j + getMax(i)

接下来我们应该更新段树调用 update(endPosIdxj, coverj) 并继续下一个段。

在处理完所有段后,可以通过调用 getMax(size(endPos)) 找到解决方案。

【讨论】:

    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多