问题描述
问题情景:在活动选择问题的基础上,为每个活动增加了权重。问题变为,一天中给定一系列活动,每个活动有一个权重。参加的活动必须是不相容的(incompatible),即在时间上不能有重叠。问如何安排一天的时间,使得参加的活动的权重和最大?
形式化定义:给定一个向量的集合
A
=
{
a
1
(
s
1
,
f
1
,
w
1
)
,
a
2
(
s
2
,
f
2
,
w
2
)
,
.
.
.
,
a
n
(
s
n
,
f
n
,
w
n
)
}
A=\{a_1(s_1,f_1, w_1),a_2(s_2,f_2,w_2),...,a_n(s_n,f_n,w_n)\}
A={a1(s1,f1,w1),a2(s2,f2,w2),...,an(sn,fn,wn)},选择
A
A
A的子集
S
S
S,满足:
s
i
≤
f
j
∨
f
i
≥
s
j
,
∀
a
i
,
a
j
∈
S
s_i\leq f_j \lor f_i\geq s_j,\forall a_i,a_j\in S
si≤fj∨fi≥sj,∀ai,aj∈S
使最大化:
∑
a
i
∈
S
w
i
\sum\limits_{a_i\in S}w_i
ai∈S∑wi
贪心算法
活动选择问题存在三种贪心思想:
- 贪心策略一:优先参加时间最短的活动
- 贪心策略二:优先参加最早开始的活动
- 贪心策略三:优先参加最早结束的活动
在不带权的活动选择问题中,我们按优先参加最早结束的活动来进行贪心,并证明了方案的最优性。但在带权活动选择问题中,我们需要引入动态规划思想进行一些改进。
动态规划
“ i i i个不冲突活动的最大权重和”可以由以下两种情况得来:
- 选择第
i
i
i个活动,则
i
i
i个不冲突活动的最大权重和 = 前
f
(
i
)
f(i)
f(i)个不冲突活动的最大权重 +
w
i
w_i
wi
- 其中 f ( i ) f(i) f(i)为选择 i i i之后在 i i i之前最后一个不与 i i i冲突的活动序号
- 不选择第 i i i个活动,则 i i i个不冲突活动的最大权重和 = 前 i − 1 i-1 i−1个不冲突活动的最大权重。
记
i
i
i个不冲突活动的最大权重和为
d
p
[
i
]
dp[i]
dp[i],则状态转移方程为:
d
p
[
i
]
=
m
a
x
{
d
p
[
i
−
1
]
,
d
p
[
f
(
i
)
]
}
dp[i]=max\{dp[i-1], dp[f(i)]\}
dp[i]=max{dp[i−1],dp[f(i)]}
动态规划的复杂度为线性 O ( n ) O(n) O(n),而事先对活动排序的时间复杂度至少为 O ( n l o g n ) O(nlogn) O(nlogn)。因此整个算法的复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。
例子:
对于上述问题,填表如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|
0 | 5 | 8 | 8 | 12 | 12 | 12 | 13 | 20 | 20 | 21 |
因此最大权值和为21。
讨论:活动排序策略
一个值得讨论的问题是,当我们在动态规划中比较两个活动的“先后”时,采用的是什么标准?在前文的动态规划中,我们沿用不带权活动选择问题的做法,使用的是结束时间进行升序排序。那么,能否选择另外两种贪心思想来排序呢?
对于最早开始优先的思想,按开始时间进行排序,显然也是可行的。这需要进行一个反序的动态规划,相当于将活动图左右翻转了一下。
对于时间最短优先的思想,则很难进行动态规划,因为动态规划最主要是利用好递归的子问题,而按时间最短优先则会选择到在中间的活动,破坏了时间的连续性,从而无法形成子问题。
附:贪心算法和动态规划算法的比较
- 贪心算法:一步步地通过增加子问题的规模来构造问题的解,并短视地(myopically)注重于当前构造当前的子问题:既不保存过去的子问题信息,也不关注更大规模的问题。
- 如果贪心算法被证明能得到最优解的话,那么它一定是高效的好算法。
- 动态规划:将问题分解为许多重叠的子问题,并通过填表将子问题的最优解合并为所求的最优解。
- 动态规划的适用范围比贪心算法的范围更广。