用给定的间隔覆盖所有数字的贪婪尝试
Posted
技术标签:
【中文标题】用给定的间隔覆盖所有数字的贪婪尝试【英文标题】:Greedy Attempt for covering all the numbers with the given intervals 【发布时间】:2014-10-28 10:31:44 【问题描述】:设
S
是可能重叠的自然数的一组区间(包含 n 个区间),N 是一个数字列表(包含 n 个数字)。
我想找到 S 的最小子集(我们称之为 P),这样对于每个数字 在我们的列表 N 中,在 P 中至少存在一个包含它的区间。 P中的区间允许重叠。
简单的例子:
S = [1..4], [2..7], [3..5], [8..15], [9..13]
N = [1, 4, 5]
// so P = [1..4], [2..7]
我认为动态算法可能并不总是有效,所以如果有人知道这个问题的解决方案(或可以转换成的类似问题),那就太好了。我正在尝试制作 O(n^2 解决方案)
这是一种贪婪的方法
P =
for each q in N: // O(n)
if q in P // O(n)
continue
for each i in S // O(n)
if q in I: // O(n)
P.add(i)
break
但这是 O(n^4).. 任何有助于创建 O(n^2) 的贪婪方法都会很棒!
谢谢!
* 更新:*我一直在抨击这个问题,我认为我有一个 O(n^2) 的解决方案!!
如果你认为我是对的,请告诉我!!!
N = MergeSort (N)
upper, lower = infinity, -1
P = empty set
for each q in N do
if (q>=lower and q<=upper)=False
max_interval = [-infinity, infinity]
for each r in S do
if q in r then
if r.rightEndPoint > max_interval.rightEndPoint
max_interval = r
P.append(max_interval)
lower = max_interval.leftEndPoint
upper = max_interval.rightEndPoint
S.remove(max_interval)
我认为这应该可行!我正在尝试找到一个反解决方案;但是是的!
【问题讨论】:
Covering all the numbers with the given intervals的可能重复 谢谢,但这与那个问题的限制略有不同。我也在尝试推导出一个 O(n^2) 算法 【参考方案1】:这个问题类似于集合覆盖问题,它是 NP 完全的(即,可以说没有比指数更快的解)。不同之处在于区间总是覆盖相邻元素(不是 N 的任意子集),这为更快的解决方案开辟了道路。
http://en.wikipedia.org/wiki/Set_cover_problem
我认为 Mike 提出的解决方案已经足够好了。但我认为我有非常简单的 O(N^2) 贪婪算法。开始就像 Mike 的一样(而且我相信 Mike 的解决方案也可以通过类似的方式改进):
你对你的 N 个数字进行排序,并将它们排序到数组 ELEM 中;复杂度 O(N*lg N);
使用二分搜索,对于每个区间 S[i],您可以识别 ELEM 中被 S[i] 覆盖的元素的开始和结束索引。比如说,你把这对数字放到数组 COVER 中,两个索引之间的差异告诉你你覆盖了多少个元素,为简单起见,我们把它放在数组 COVER_COUNT 中;复杂度 O(N*lg N);
您引入索引指针 p,它显示直到 ELEM 中的哪个元素,您的 N 已经被覆盖。您设置 p = 0,这意味着最初覆盖到第 0 个(排除)的所有元素(即没有元素);复杂度 O(1)。此外,您引入了布尔数组 IS_INCLUDED,它反映了区间 S[i] 是否已包含在您的覆盖集中。复杂度 O(N)
然后你从ELEM中的第0个元素开始,看看包含ELEM[0]并且覆盖范围更大的COVER_COUNT[i]的区间是多少。假设它是第 i 个区间。然后我们通过将 IS_INCLUDED[i] 设置为 true 将其标记为包含。然后将 p 设置为 end[i] + 1 其中 end[i] 是 COVER[i] 对中的结束索引(实际上现在所有元素 til end[i] 都被覆盖了)。然后,知道 p 您更新 COVER_COUNT 中的所有元素,以便它们反映每个间隔覆盖的尚未覆盖元素的数量(这可以在 O(N) 时间内轻松完成)。然后对 ELEM[p] 执行相同的步骤并继续直到 p >= ELEM.length。可以观察到整体复杂度为O(N^2)。
您在 O(n^2) 中完成,并且在 IS_INCLUDED 中,对于包含在最佳覆盖集中的 S 的间隔,您是正确的
让我知道这个解决方案对你来说是否合理,如果我计算得很好。
附:只是想补充一点,算法找到的解决方案的最优性可以通过归纳和矛盾来证明。通过矛盾,很容易证明至少一个最优解包括那些覆盖元素 ELEM[0] 的最长区间。如果是这样,通过归纳,我们可以证明对于算法中的每个下一个元素,我们可以继续遵循选择相对于剩余元素数量最长的间隔和覆盖最左边尚未覆盖的元素的间隔的策略。
【讨论】:
嘿Heorhi,非常感谢!!您的解决方案非常复杂!我刚刚用我发明的一个我认为应该可行的解决方案更新了这个问题!但我不完全确定;你能检查出来吗? 我在这里回答,因为我没有足够的声誉来评论原始问题。您的解决方案似乎与我的类似,但您不必考虑间隔的绝对长度,而是必须根据先前迭代后仍未发现的数字来考虑长度。不过,您的解决方案仍将保持 O(N^2)。举例来说,这里是您的解决方案无法找到最优解的地方:N= 1, 4, 7 S= (1,4)(2,6)(6,7)。您的解决方案将包括所有间隔,而仅包括 S[0] 和 S[2] 嗯,非常感谢!我正在检查这个。所以你提议我把if r.rightEndPoint < max_interval.rightEndPoint
改成 if |r.rightEndPoint - r.leftEndPoint| < |max_interval.rightEndPoint - max_interval.leftEndPoint|
?德拉特,我以为我拥有它!我现在正在检查。
嗯,我刚刚检查了一下,用我的算法得到了 S[0] 和 S[2] 以及那个反例。在if (q>=lower and q<=upper)=False
,当lower等于1,upper等于4,所以S[1]不通过。
即我们先到n[0](也就是1)先抢S[0],设置upper为4,lower为1;然后转到 n[1],即 4;它已经在上下之间,跳过!然后转到 n[2],添加 S[2] 并将上限设置为 7,将下限设置为 6。【参考方案2】:
我不确定,但有些人是这样想的。
1) 为每个区间创建一个列表,其中包含来自 N
的元素在区间中包含,它将采用 O(n^2)
让我们称其为 Q[i]
为 S[i]
2) 然后按照Q[i]
、O(n*lg(n))
的长度对我们的S
进行排序
3)从N
O(n)
和Q[i+1]...Q[n]
中抛出这个数组,不包括Q[i]
=O(n^2)
4) 当N
不为空时重复2。
不是O(n^2)
,而是O(n^3)
,但如果你可以使用hashmap,我认为你可以改进它。
【讨论】:
非常感谢,是的,O(n^2)
似乎很难得到它。我一直在尝试很多东西。再次感谢!以上是关于用给定的间隔覆盖所有数字的贪婪尝试的主要内容,如果未能解决你的问题,请参考以下文章