我正在关注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。有没有办法消除这一点。如果我想使用数组存储解决方案,我应该存储什么?
答案 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)运行时复杂度:
由于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)支配:
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