动态规划之活动选择--算法分析和描述

最近复习了算法导论部分内容,感觉好陌生啊。记得研一老师只上了算法入门,其余的章节班级分组学习讲解,我只记得我们那一组负责的内容,有关图论、Dijkstra之类的。这两天看了动态、贪心算法,感觉这个真的很不错,以前只忙于准备自己的章节,也没有细细学习和体会。
总体感觉(个人的理解,不一定准确),动态规划的核心步骤是分析问题,描述出解的递推公式,这个类似于高中学得数列只是更加复杂一些,毕竟数列大部分能笔算出来,而动态规划中就必须借助程序来解了。然后自底向上计算出解。所谓自底向上,从初始值开始计算各个值,并维护一个table来存储这些值,后面计算的值往往会用到前面计算的值,有点空间换时间的意思。
直接写例子吧,这个例子实际上用贪心算法更加简单易解,这里用动态规划实现旨在学习动态规划了。假设有n个活动集合S = {a1,a2,.....an},每个活动ai有开始时间si小于其结束时间fi,即ai活动的时间区间[si, fi),如果[si, fi)和[sj, fj)互不重叠,则称ai和aj两个活动为兼容,问题:选出一组最大(包含最多的活动个数)的一组兼容活动。

1.首先为简化问题,我们对集合S以结束时间先后排序,即有
f0 < f1 < f2 ... < fn+1 时间复杂度为 nlg(n)
2.找最优子结构:
定义 S(ij)是S中活动的子集,其中每个活动在ai结束之后开始,且在aj开始之前结束。并引入虚拟活动a0与an+1,f0 = 0, sn+1 = NaN(暂且表示无穷大吧)。Sij = empty(暂且表示空集)。于是有:
a) 当 i >= j 时,Sij = empty
b) 假设Sij的解包含ak,即有fi <= sk < fk <= fj,则 Sij = Sik ∪ ak ∪ Skj
若用Cij表示Sij的活动个数,有Cij = Cik + 1 + Ckj

3. 于是有递归解:
Cij = 0 如果 Sij = empty
Cij = max{Cik + Ckj + 1} i < k < j,ak属于Sij 如果Sij != empty

用C[i][j]来记录中间计算的Cij的值,A[i][j]来记录中间计算的Sij集合,所以可以写出算法了:

SELECT_ACTIVITY(s,f,n)
for i <- 0 to n+1
do for j <- 0 to i
do c[i][j] <- 0;
A[i][j] <- empty;
//一半的table值已填满,然后以与对角线平行一行一行填写剩下的半个table

for t <- 1 to n+1
do for i <- 0 to n+1-t
do j = i + t;
if f[i] >= s[j] //第i个活动结束之前第j个活动已开始
then c[i][j] <- 0;
A[i][j] <- empty;
else
for k <- i+1 to j-1
do
if s[k] >= f[i] and f[k] <= s[j]
then
if c[i][j]< c[i][k] + c[k][j] + 1
then c[i][j] <- c[i][k] + c[k][j] + 1;
A[i][j] <- A[i][k] ∪ k ∪ A[k][j];

这个本是贪心算法的一个例子,这里是学习动态规划,所以用了比贪心算法繁琐的解法。呵呵,明天将伪代码改称java代码实现并分析之。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值