问题描述
- 任务 j j j开始时间为 s j s_j sj,完成时间为 f j f_j fj,权重为 w j > 0 w_j > 0 wj>0。
- 两个任务如果执行时间没有覆盖,则两个任务是兼容的
- 目标:找到一个彼此兼容且权重最大的任务子集
-
动态规划求解思路( n l o g n nlogn nlogn)
将任务按照结束时间升序排列:
f
1
≤
f
2
≤
⋯
≤
f
n
f_1 \leq f_2 \leq\dots\leq f_n
f1≤f2≤⋯≤fn
设
p
(
j
)
p(j)
p(j)是与任务
j
j
j相容的最大下标的任务,如:
p
(
8
)
=
1
,
p
(
7
)
=
3
,
p
(
2
)
=
0
p(8)=1,p(7) = 3, p(2)=0
p(8)=1,p(7)=3,p(2)=0 (通过二分搜索计算)
设
O
P
T
(
j
)
OPT(j)
OPT(j)为对于只含有
1
,
2
,
…
,
j
1,2,\dots,j
1,2,…,j(前
j
j
j个任务)的可相互兼容子集最大权重
目标:找到一个彼此兼容且权重最大的任务子集
①
O
P
T
(
j
)
OPT(j)
OPT(j)不选择任务
j
j
j,那么它一定是前
j
−
1
j-1
j−1个任务的最优解,即
O
P
T
(
j
−
1
)
OPT(j-1)
OPT(j−1)。
②
O
P
T
(
j
)
OPT(j)
OPT(j)若选择了任务
j
j
j,那么它一定是前
p
(
j
)
p(j)
p(j)个任务的最优解+
w
j
w_j
wj,即
O
P
T
(
p
(
j
)
)
+
w
j
OPT(p(j))+w_j
OPT(p(j))+wj
综上递推式如下:
时间复杂度分析
- 自顶而下的递归算法是指数时间的,因为会重复计算子问题,不带记忆性,最坏计算
O
P
T
(
j
)
OPT(j)
OPT(j)复杂度为
1.61
8
n
1.618^n
1.618n(介于
2
n
\sqrt{2}^n
2n~
2
n
2^n
2n之间)
①最慢规模减少策略考虑, p ( j ) p(j) p(j)每次减少2,即 p ( j ) = j − 2 p(j) = j-2 p(j)=j−2,如果每次 p ( j ) p(j) p(j)只减少1,则 p ( j ) = j − 1 p(j) = j-1 p(j)=j−1,则 O P T ( j − 1 ) = O P T ( p ( j ) ) OPT(j-1) = OPT(p(j)) OPT(j−1)=OPT(p(j)),那么一定有 O P T ( p ( j ) ) + w j ≥ O P T ( j − 1 ) OPT(p(j))+w_j\geq OPT(j-1) OPT(p(j))+wj≥OPT(j−1),这样一半的分支就不用继续递归下去了,会减掉一半的计算量,两个分支将变成1个分支,反而规模减少更快。
②因此最坏情况是按规模1步长减少(不变形式分支)和按规模2步长减少(可变形式分支)的混合结果,因此是两种满二叉树的中间值,即介于 2 n \sqrt{2}^n 2n~ 2 n 2^n 2n,两个满二叉树的层数不同(一个层数为 ⌊ n 2 ⌋ \lfloor \frac{n}{2} \rfloor ⌊2n⌋,一个层数为 n n n),由于规模减少速度的不同。 - 自底向上带记忆性的算法时间复杂度为
n
l
o
g
n
nlogn
nlogn
①根据完成时间排序所需时间:归并排序 O ( n l o g n ) O(nlogn) O(nlogn)
②对于每个 j j j计算 p [ j ] p[j] p[j]:二分查找 O ( n l o g n ) O(nlogn) O(nlogn)
③计算 O P T ( j ) OPT(j) OPT(j):每次计算得到一个值,一共n个, O ( n ) O(n) O(n) - 最终找最优方案,伪代码:
最多调用 n 次 n次 n次,因此复杂度为 O ( n ) O(n) O(n)
例题说明
求解最优值表格如下:
求解最优方案:
看是否选了当前任务
j
j
j(根据递推式),若选了,则跳到
O
P
T
(
p
(
j
)
)
OPT(p(j))
OPT(p(j)),继续查找方案;若没选,则跳到
O
P
T
(
j
−
1
)
OPT(j-1)
OPT(j−1),继续查找方案。