给定一个时间间隔列表,我需要找到最大非重叠间隔的集合。
例如,
如果我们有以下间隔:
[0600, 0830], [0800, 0900], [0900, 1100], [0900, 1130],
[1030, 1400], [1230, 1400]
此外,时间必须在[0000, 2400]
范围内。
最大非重叠间隔集是[0600, 0830], [0900, 1130], [1230, 1400]
。
据我所知,最大设定包装是NP-Complete。我想确认我的问题(包含仅包含开始和结束时间的间隔)是否也是NP-Complete。
如果是这样,有没有办法在指数时间内找到最佳解决方案,但需要更智能的预处理和修剪数据。或者如果有一个相对容易实现的固定参数易处理算法。我不想去寻找近似算法。
答案 0 :(得分:25)
这不是NP-Complete问题。我可以想到使用动态编程的O(n * log(n))
算法来解决这个问题。
假设我们有n个间隔。假设给定范围是S
(在您的情况下,S = [0000, 2400]
)。假设所有区间都在S
之内,或者在线性时间内消除S
以内的所有区间。
处理前:
A[n]
。
O(n * log(n))
时间Next[n]
个n
整数的数组i,
。
n
的结束点不存在此类起点,我们可能会将Next[i]
分配给O(n * log(n))
。O(n * log(n))
时间内通过枚举所有间隔的n个终点来执行此操作,并使用二进制搜索来查找答案。也许存在线性方法来解决这个问题,但这并不重要,因为上一步已经花了[A[i].begin, S.end]
时间。DP:
f[i]
中的最大非重叠间隔为f[0]
。然后f[n] = 0
就是我们想要的答案。f[i] = max{f[i+1], 1 + f[Next[i]]}
; B[n]
上面的解决方案是我第一眼看出问题的解决方案。在那之后,我还想出了一种更简单的贪婪方法(但在大O符号意义上并不快):
(使用与上述DP方法相同的符号和假设)
预处理:按结束点对所有间隔进行排序。假设我们得到n个区间的数组int ans = 0, cursor = S.begin;
for(int i = 0; i < n; i++){
if(B[i].begin >= cursor){
ans++;
cursor = B[i].end;
}
}
。
贪婪:
{{1}}
以上两个解决方案出自我的想法,但您的问题也称为活动选择问题,可在维基百科http://en.wikipedia.org/wiki/Activity_selection_problem上找到。
此外,算法简介在16.1中深入讨论了这个问题。