算法导论习题15-动态规划

动态规划: 
本章书中举的几个例子很有代表性,每一个例子有着划分子问题的方法。可以看到,书中的例子可以作为动态规划算法的模式,很多问题都可以用类似于他们的方法来解决。
1 流水线调度
2 矩阵链乘法
3 最长公共字符串问题

字符串相似
1 一个字符串是其他字符串的字串
2 一个字符串可以通过小的改动变成另一个字符串
3 两个字符串拥有公共字串,这个字串不需要是连续在两个字符串出现,但是要按相同的顺序。

1 用kmp算法解. 32章
2 也可以用动态规划解,problem 15-3

3 是最大公共字符串问题 LCS,用动态规划解,第15章
LCS,关键在于算法如何优化。有两种方式优化,一个是优化计算公共字符串长度的临时表的空间复杂度,一个是优化重构公共字符串内容的表的空间复杂度。

习题15.4-2
蛮容易的,检查a[i][j] 与a[i-1][j] a[i][j-1] a[i-1][j-1]; 如果有a[i][j]=a[i-1][j-1] + 1的话,打印这个值。
否则,找a[i-1][j] 与 a[i][j-1]的最大的值(如果两个相等,说明有多个答案)作为新的a[i][j],如此迭代;

习题15.4-4
空间复杂度的优化现阶段不是我的重点,以后回来再看。

习题15.4-5
分析:
举个例子haibjcd的最长递增子链是abcd, 定义A[0..i]为A的第0个到第i个之间的字符组成的字符串,很自然的一种构造子问题的方式是通过减少i的值来缩小问题的规模,从例子可以看到,问题解的一部分ab并不是子问题haibj的最优解。所以这个问题不具备最优子结构。所以虽然可以用递归的方式来解决,但是问题解决的效率要低很多。每当读取一个新的字符,因为不具备最优子结构,不能直接使用新字符与子问题最优解,即子问题的最长递增字串直接比较得到新的最优解。就像这个例子,不能直接将c与haibj的最优解hij的j相比较,然后得出hij是haibjc的最优解的结果。

通过这个不具备最优子结构问题的例子,使得我对动态规划有了更加深入的理解。
动态规划和贪心算法能够很好的解决很多最优化的问题!离散的最优化问题都要通过搜索来完成,而对于一般的穷举搜索,算法复杂度都是指数级的,很不现实。如果一个问题具有动态规划的要素,可以用动态规划来解决,那么可以很容易在多项式时间解决问题(算法导论对动态规划算法分析有比较好的说明,动态规划算法复杂度与总的子问题数量和确定子问题最优解的代价有关)。更进一步,如果一个问题具有贪心的元素,可以用贪心法来解决,那么会有更好的效率,正如 <算法导论> 介绍贪心法,贪心法确定子问题最优解的代价为常数时间。

《人工智能-一种现代的方法》中介绍了搜索问题的解题步骤。首先是goal formulation,意思是确认问题的解目标;接下来的工作是problem formulation,主要确定搜索的所有的状态states和在所确定的状态上能够做的改变规则operators。Problem formulation很重要,它需要我们对问题和解有很好的认识,而且好的Problem formulation可以提高算法的效率。例如,回溯法需要搜索指数级的状态值才能找到所有的解,但是使用另外一种方法,可以把整个搜索的步数降低到几千步。对于同样的问题,从不同的角度分析,有不一样的结果。同样的问题,不一样的子问题定义方式,有不一样的结果。从下面也将看到,不能离开子问题的定义方式来讨论最优子结构。

如果采用另外一种定义子问题的方式,字符串的最长单调递增字串是具有最优子结构的。定义A[i, j]为字符串第i个和j个字符之间的字串,从第k个字符断开将这个串分成两个更小的字串,通过这样的方式来讲问题规模缩小,很容易知道它是具有最优子结构的。也很容易得到一个递归式,可以看到,它与矩阵链乘法的相识。
A[i, j] = min{for k in (i, j) : A[i, k] + A[k, j] };  when  i!=j /
A[i, j] = 0;   when   i=j
总的子问题是 n^2个,确定最优子问题的代价是 O(n),所以,算法总复杂度是 O(n^{3} )

但是这个问题有比动态规划效率更高的方法。动态规划计算了过多的无用的子问题,如果可以避免那些多余的计算,算法效率会高很多。定义s_{ij}为第i个字符和j个字符之间的字串,A[i][j]为字符串从i到j位置的最长递增字串长度。从左到右循环计算A[0][j],当考虑到第j个字符时,需要将它分别与{ s_{k{j-1}} ,  0<k<j-1}, 最多与j-1个递增字符串的最大值比较。迭代的计算式如下:

A[i][j] = A[i][j-1]  如果 A[j]比i到j-1的最长递增字串最大值要小
A[i][j] = A[i][j-1] + 1如果 A[j]比i到j-1的最长递增字串最大值要打
A[0][j] = max{ {forall k in (0,j): A[k][j] } }
这样每个字符加入都要进行O(n)次操作,有n个字符,总算法复杂度是O(n^{2} )

更加好的算法是使用分治法,将两个字符串 s_{ik}s_{kj}的所有递增字符串合并的代价是 O(n),得到时间复杂度的递归式,从顶自下,每次将字符串分成两个子字符串,可以得到时间复杂度的递归式:
T(n)=T(n/2) + O(n); 根据《算法导论》第四章介绍的主定理得到,时间复杂度是是 O(nlg(n) )

从这个习题可以看到,动态规划和贪心算法是比较通用的算法,优点就是比较容易设计和实现,往往还有比这种通用算法效率更好的方法,习题16-1-3也可以证明这一点。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值