算法导论习题分析——15章 动态规划

15-1 有向图最长简单路径

习题分析

由题意可知,有向无环图,最长路径长度,无需考虑搜索重复节点、路径成环等问题。
使用动态规划思路分析:

  1. 首先证明最优子结构性质。 首先确定一个问题的子问题:在求节点 v i v_i vi v j v_j vj的最长距离时,要考虑其相邻节点到 v j v_j vj的最长距离。即:子问题为:相邻节点到目标节点的最长距离。又由于是有向图,因此不需要考虑节点重复的情况。
    反证法证明最优子结构:假设子问题的解不是子问题的最优解,即选取相邻节点到终点的非最长路径。将最长路径替换此解,原问题即可得到更优解,与题目要求相悖。最优子结构得证。
  2. 解的结构设计:直观的想法是建立二维数组 c [ i ] [ ] j ] c[i][]j] c[i][]j]保存 v i v_i vi v j v_j vj的最长距离,但注意到题目中目标节点固定,因此数组的 j j j坐标恒定。因此用一维数组即可。
  3. 选择的保存:每次选择可记录下来,用以复原路径。可用一维数组保存每个节点选择的子节点,直到目标节点。复原路径时按选择顺序输出即可。

代码实现

15-1 Longest Route

15-2 最长回文子串

习题分析

给定一个字符串,要求其最长的回文子串。
按照动态规划的方法分析此问题:

  1. 证明最优子结构性质。首先探讨解的形式:原问题的一个解,形式为选择一个子串,证明它是回文字符串,则两端字符须相等。这个解的子问题为:除去两端字符,得到的子串也是回文字符串。再证明最优子结构:设原问题的子问题解不是子问题最优解,即选择的子串不是最长回文子串,则存在更长的回文字符串,将其作为子问题的解,原问题得到更优解,与题意相悖,性质得证。
  2. 刻画解的结构。设 c i c_i ci为长度为 l l l的回文字符串的起始字符,则使用标记数组 C [ i ] [ l ] = 1 C[i][l]=1 C[i][l]=1表示。对于每一个字符,都是长度为1的回文字符串的起始字符。再对长度为2的回文子串特别处理。因此 l l l从3开始,对每一个字符 c i c_i ci考察 c i + l − 1 c_{i+l-1} ci+l1是否和其相等,再考察 c i + 1 c_{i+1} ci+1是否为长度 l − 2 l-2 l2的回文串的起始字符。若两个条件都满足,则 c i c_i ci是长度为 l l l的回文串的起始字符, C [ i ] [ l ] C[i][l] C[i][l]置1。
  3. 找到最长的回文子串:每次标记数组 C C C更新时,记录起始位置和长度,处理结束后从原字符串截取即可。

代码实现

15-2 Palindrome

15-3 双调巡游

习题分析

给定一组二维坐标,其x坐标各不相同,找出从最左端点出发,严格向右行走至最右端点,后严格向左行走返回最左端点的最短路径。二维坐标已按照x坐标从小到大排好序
根据动态规划的思想分析:

  1. 考虑从某一节点 V i V_i Vi出发严格向左至起始点后严格向右至某点 V j V_j Vj,这条路径为 L i j L_{ij} Lij。维持 L i j L_{ij} Lij为从 V i V_i Vi经过起点到 V j V_j Vj的最短路径,按照 x x x坐标从小到大的顺序不断扩充路径包含的点数,直到 V i = V j V_i=V_j Vi=Vj,此时 V i = V j V_i=V_j Vi=Vj等于终点, L i j L_{ij} Lij即为所求最短路径。
  2. 证明最优子结构性质。假设 V i V_i Vi V j V_j Vj已知, L i j L_{ij} Lij的最优解为当前的问题,子问题为:找到从 V i V_i Vi开始,到当前路径里所有的点 V k V_k Vk终止,并经过 L i j L_{ij} Lij中除 V j V_j Vj外所有节点的路径 L i k L_{ik} Lik,求在这种链接情况下 V i V_i Vi V j V_j Vj的距离 l i k + d ( k , j ) l_{ik}+d(k,j) lik+d(k,j),其中 l i k l_{ik} lik L i k L_{ik} Lik的长度, d ( k , j ) d(k,j) d(k,j) V k V_k Vk V j V_j Vj之间的距离。找到子问题之后,使用反证法证明:假设选择的子问题的解不是最优解,则选择子问题中距离最短的连接方式作为子问题的解,可以得到原问题的最优解,与题意相悖,得证。
  3. 解结构的处理。考虑以下两种情况:
    • i < j − 1 i<j-1 i<j1。这种情况意味着 V i V_i Vi V j − 1 V_{j-1} Vj1的左边,根据双调巡游的性质,由于 V j − 1 V_{j-1} Vj1不是路径起点,则 V j − 1 V_{j-1} Vj1必定是 L i j L_{ij} Lij中连接 V j V_j Vj的节点。此时 l i j = l i j − 1 + d ( j − 1 , j ) l_{ij}=l_{ij-1}+d(j-1,j) lij=lij1+d(j1,j)
    • i = j − 1 i=j-1 i=j1。这种情况意味着 L i j L_{ij} Lij中连接 V j V_j Vj的节点不确定,需要搜索。从 V 0 V_0 V0开始遍历,直到 V j − 2 V_{j-2} Vj2,考虑这些点作为子问题路径终点,即这些节点作为 L i j L_{ij} Lij中连接 V j V_j Vj的节点的情况,计算 L i j L_{ij} Lij可能情况中最短的路径,保留作为 L i j L_{ij} Lij
      最后一种可能, i = j = n i=j=n i=j=n,即 V i , V j V_i,V_j Vi,Vj都为最右端点的情况, L k n L_{kn} Lkn为从 V k V_{k} Vk出发,到 V n V_n Vn的最短路径,考察所有可能的 k k k,将 V k V_k Vk V n V_n Vn连接即可得到双调巡游的闭环,求这些可能闭环的最短路径作为 L n n L_{nn} Lnn

代码实现

15-3 Bitonic Tours

15-5 编辑距离

习题分析

字符串 A A A转化为字符串 B B B,可以经过如下变换:复制,替换,删除,插入以及旋转( a i = b j + 1 , b j = a i + 1 a_i=b_{j+1},b_j=a_{i+1} ai=bj+1,bj=ai+1。规定替换,删除,插入的代价为1,其他操作代价为0。求出最小代价和变换过程。
按照动态规划的思想思考这个问题:

  1. 证明最优子结构性质:假设 A A A的前 i i i A i A_i Ai转化为 B j B_j Bj,子问题为 A i − 1 A_{i-1} Ai1转化为 B j − 1 B_{j-1} Bj1, A i − 1 A_{i-1} Ai1转化为 B j B_j Bj A i A_i Ai转化为 B j − 1 B_{j-1} Bj1。可以选择的变换方式有替换,删除,插入,也可能有复制和旋转。假设从操作中选择一个作为子问题的解,而不是最优解,则选择最优解会使 A i A_i Ai B j B_j Bj 的代价更优,与题意相悖,得证。
  2. 解的结构:设二维数组 c [ i ] [ j ] c[i][j] c[i][j]表示 A i A_i Ai B j B_j Bj的最小代价,则复制的情况下, c [ i ] [ j ] = c [ i − 1 ] [ j − 1 ] c[i][j]=c[i-1][j-1] c[i][j]=c[i1][j1],替换的情况下, c [ i ] [ j ] = c [ i − 1 ] [ j − 1 ] + 1 c[i][j]=c[i-1][j-1]+1 c[i][j]=c[i1][j1]+1,删除的情况下, c [ i ] [ j ] = c [ i − 1 ] [ j ] + 1 c[i][j]=c[i-1][j]+1 c[i][j]=c[i1][j]+1,插入的情况下, c [ i ] [ j ] = c [ i ] [ j − 1 ] + 1 c[i][j]=c[i][j-1]+1 c[i][j]=c[i][j1]+1,旋转的情况下, c [ i ] [ j ] = c [ i − 2 ] [ j − 2 ] c[i][j]=c[i-2][j-2] c[i][j]=c[i2][j2]。在这些可能的取值内取最小。
  3. 构造变换过程:在每一步记录变换选择,反推回去即可构造变换过程。

代码实现

15-5 Editorial Distance

15-7 译码算法

习题分析

在有向图内每个边对应一个标签和一个概率,概率代表随机游走选择该边的概率,所有节点出边概率和为1。现给定起始点,给定标签序列,求这样一个游走路径,使路径上标签一一对应,并累计概率最大(概率采用乘积运算)。
按照动态规划算法分析:

  1. 首先确定子问题。求长度为 l l l的路径的子问题为求符合要求的长度为 l − 1 l-1 l1的路径,并选择一条符合条件的边组成概率最大的 l l l长的路径。在此子问题的最优解就是问题的最优解,或者说找到概率最大的 l − 1 l-1 l1长的路径不保证 l l l长路径也概率最大(好像不符合最优子结构哦)。不过鉴于子问题的定义是找到 l − 1 l-1 l1长的路径并找到路径使 l l l长概率最大,就说它是最优子结构好了(毕竟在这种定义下子问题跟原问题基本上是一样的)。
  2. 设计解的结构。由于不具有常规意义上的最优子结构,只得采用搜索,把所有满足 l − 1 l-1 l1的路径及相应概率记录下来用来搜索 l l l长的路径,具体实现方法类似SPFA,只是深度每增加一层更新一下搜索队列。
  3. 从符合路径标签的 l l l长路径里找到最大概率的就是问题的解(硬生生把动态规划做成了广搜)。

代码实现

15-7 Decoding

15-9 字符串拆分

习题分析

一个字符串,给定一个切割序列 M M M,每个元素 m i m_i mi代表在原字符串第 m i m_i mi个字符后切割。切割获得两个子串,长度 L L L的字符串在任意位置切割一刀所需要代价均为 L L L。求合理的切割顺序,使得总代价最小。
按照动态规划的思路分析问题:

  1. 确定子问题:在某一位置切割之后,有两个子串,子问题为合理的切割子串使得子串代价最小。证明最优子结构:假设子串切割不是最优切割,则选择最优子串切割作为子问题解,原问题可得更优解,与题意相悖,得证。
  2. 确定解的结构:可知,在某一位置切割,代价为原字符串长度,则此字符串的最小代价为:在此字符串内遍历可以切割的位点,得到两个子字符串的最小代价,再加上字符串长度。同时对于不可切割的字符串,代价为零。采用自顶向下带备忘机制的设计, c [ i ] [ j ] = min ⁡ { c [ i ] [ k ] + c [ k + 1 ] [ j ] + j − i + 1 } c[i][j]=\min\{c[i][k]+c[k+1][j]+j-i+1\} c[i][j]=min{c[i][k]+c[k+1][j]+ji+1} for all possible k k k
  3. 确定切割顺序:两个不同字符串之间的切割是独立的,所以仅对不同的子串维护一个最优切割点,即对pair ( i , j ) (i,j) (i,j)维护一个切割点 k k k。输出切割顺序时递归的输出 i , j i,j i,j对应的 k k k,并对 i , k i,k i,k k + 1 , j k+1,j k+1,j递归的做相同处理。

代码实现

15-9 Divide String


未完待续…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值