加权区间调度解决方案构建

时间:2011-11-06 03:56:05

标签: algorithm dynamic-programming

我正在关注tardos书以学习动态编程。我对加权区间调度问题的解决方案构造部分有疑问 建议不要使用另一个数组来存储解决方案,我们应该以这种方式使用相同的成本数组:

Find-Solution(j)
 if  j = 0 then 
   output nothing
 else
   If Vj + M[p(j)] >= M[j-1] then
    output j together with the result of find-solution(p(j))
 else
   output find-solution(j-1)
 endif

我的问题是找到p(j)它应该花费O(n)时间,并且我们可以使这些递归调用O(n)时间使这个算法成为O(n ^ 2)。但在书中声称这是O(n) 我们也做了几乎相同的计算,再次找到成本数组m。有没有办法消除这一点。如果我想使用数组存储解决方案,我应该存储什么?

4 个答案:

答案 0 :(得分:1)

我认为他们的分析假设你已经预先计算了p的所有值,在这种情况下,方法的运行时确实是O(n)。计算p的值将采用O(n log n)。

在此处查看如何计算p:http://www.cs.cornell.edu/courses/cs4820/2010su/handouts/computation-of-p-j.pdf

要查看有关算法的类似分析:http://www.cs.uiuc.edu/class/fa08/cs473/Lectures/lecture12.pdf。在那里它还声称计算需要O(n)。但是你最后会看到他对总运行时间的分析,包括计算p是O(n log n)。

答案 1 :(得分:1)

我在这篇文章中解释了算法及其复杂性分析:http://kartikkukreja.wordpress.com/2013/10/06/weighted-interval-scheduling-problem/

答案 2 :(得分:1)

查找p[1..j]将花费O(n log n)运行时复杂度:

  • 你必须为1..j中的每个间隔计算它:O(n)
  • 对于每个间隔,您必须找到最右边的相互兼容(非重叠)间隔:O(log n)和二分搜索

由于O(n)和O(log n)都在增长(当n增长时),我们必须将产品作为最终的复杂性,这就是为什么找到所有p [1..j]是O(n log) n)中。

现在,在find-solution上:它是O(n),因为它假定了预先计算的值。这是合乎逻辑的,因为我们希望专注于此方法中的OPT遍历,并且对如何计算p(j)不感兴趣。

最后,当我们有几个Big-Oh计算,并且需要找到它们的总和时,显性函数定义了总复杂度。如果在我们的情况下我们有:

  • O(n log n)找到p [1..j]
  • O(n)使用find-solution()
  • 查找实际间隔
  • O(n log n)按完成时间排序间隔
  • O(n)迭代地构建OPT [1..j]

他们的总和将由O(n log n)支配:

O(n log n)+ O(n)+ O(n log n)+ O(n)= O(n log n)

因此整体算法性能为O(n log n)。

答案 3 :(得分:0)

import collections
import bisect
import time
from datetime import datetime

"""
Weighted Interval scheduling algorithm.
Runtime complexity: O(n log n)
"""

class Interval(object):
    '''Date weighted interval'''

    def __init__(self, title, start, finish):
        self.title = title
        self.start = int(start)
        self.finish = int(finish)
        self.weight = self.finish - self.start

    def __repr__(self):
        return str((self.title, self.start, self.finish, self.weight))


def compute_previous_intervals(I):
    '''For every interval j, compute the rightmost mutually compatible interval i, where i < j
       I is a sorted list of Interval objects (sorted by finish time)
    '''
    # extract start and finish times
    start = [i.start for i in I]
    finish = [i.finish for i in I]
    print start
    print finish
    p = []
    for j in xrange(len(I)):
        i = bisect.bisect_right(finish, start[j]) - 1  # rightmost interval f_i <= s_j
        print j, i
        p.append(i)

    return p

def schedule_weighted_intervals(I):
    '''Use dynamic algorithm to schedule weighted intervals
       sorting is O(n log n),
       finding p[1..n] is O(n log n),
       finding OPT[1..n] is O(n),
       selecting is O(n)
       whole operation is dominated by O(n log n)
    '''

    I.sort(lambda x, y: x.finish - y.finish)  # f_1 <= f_2 <= .. <= f_n
    p = compute_previous_intervals(I)

    # compute OPTs iteratively in O(n), here we use DP
    OPT = collections.defaultdict(int)
    OPT[-1] = 0
    OPT[0] = 0
    for j in xrange(1, len(I)):
        OPT[j] = max(I[j].weight + OPT[p[j]], OPT[j - 1])

    # given OPT and p, find actual solution intervals in O(n)
    O = []
    def compute_solution(j):
        if j >= 0:  # will halt on OPT[-1]
            if I[j].weight + OPT[p[j]] > OPT[j - 1]:
                O.append(I[j])
                compute_solution(p[j])
            else:
                compute_solution(j - 1)
    compute_solution(len(I) - 1)

    # resort, as our O is in reverse order (OPTIONAL)
    O.sort(lambda x, y: x.finish - y.finish)

    return O

if __name__ == '__main__':
    I = []
    I.append(Interval("Summer School" , "2", "10"))
    I.append(Interval("Semester 1" , "1", "9"))
    I.append(Interval("Semester 2" , "11", "15"))
    I.append(Interval("Trimester 1" , "15", "20"))
    I.append(Interval("Trimester 2" , "14", "21"))
    I.append(Interval("Trimester 3" , "4", "11"))
    I.append(Interval("Trimester 4" , "15", "22"))
    O = schedule_weighted_intervals(I)
    print O