部分重叠时间的加权活动选择

时间:2016-11-25 11:18:44

标签: algorithm

我们假设我们有n个时间表。每个时间表i具有权重w(i),准备时间prep(i)和休息时间rest(i)。

准备时间意味着如果我们选择时间表i,我们有义务不选择时间表i - prep(i),i - prep(i)+ 1 ... i-1。

休息时间意味着如果我们选择shedule i,我们有义务不选择shedules i + 1,i + 2 ... i + rest(i)

我们的任务是根据上述限制选择合适的时间表,以便最大化W。

注意:对于i = 1,我们忽略prep(i)。我们假设我们已经准备好了。对于i = n,忽略休息(i)。

限制:一个时间表的准备时间可能与另一个时间表的休息时间重叠。举个例子,如果我们有rest(5)= 2,prep(8)= 2,我们可以选择两个时间表。 rest(5)= 2表示如果我们选择5,则不允许选择6和7。 Prep(8)= 2表示如果我们选择8,则不允许选择6和7。所以我们可以选择5和8。

此任务最合适的算法是什么?

如果不是限制,我们可以说每个时间表都有开始时间i - prep(i)和结束时间i + rest(i)。我们会有一个加权活动选择问题,所以我们可以用贪心算法得到一个最优的O(nlogn)。但是限制破坏了我的计划。

1 个答案:

答案 0 :(得分:1)

f(i)成为最佳答案,以便i - 活动是最后一个。如果ji,我们可以从活动j < prep(i)转到活动j + rest(j) < i。换句话说,f(i) = (max of f(j) among all valid j such that j < prep(i) and j + rest(j) < i) + 1。这个公式导致了一个简单的O(N^2)解决方案。

但我们可以做得更好!让我们保持一个持久的分段树以获得最大的操作(数组中每个位置的一个版本)。最初,它充满了零。对于固定的i,我们转到prep(i) - 1版本并在[0, i - 1]范围内执行最大查询。然后f(i)是此最大值加1的值。之后,我们使用i + rest(i)更新位置f(i)中的树(即创建新版本)。就是这样。

我们O(N)获得最大值并将一个元素查询更新为持久段树,因此解决方案需要O(N log N)时间和空间,这看起来非常好。但是,它似乎相当复杂。

现在让我们摆脱持久性。我们可以保持“正常”(即非持久性细分树),并在我们到达i之后用f(i)更新位置j = i + rest(i)中的值(通过保留,让我们说,在每个位置添加的元素向量)。我们不再需要关心第二个限制了。因此,f(i)[0, prep(i) - 1]范围内的最大值加1。找到f(i)后,我们会将i + rest(i)位置添加到要添加的向量中。

它仍然使用O(N log N)时间,但空间复杂度现在是线性的,我们不再需要持久的分段树(事实上,每次更新只能增加值,我们需要一个最大值前缀,所以我们可以在这里使用二进制索引树而不是段树。