算法导论 — 思考题15-4 整齐打印

整齐打印)考虑整齐打印问题,即在打印机上用等宽字符打印一段文本。输入文本为 n n n个单词的序列,单词长度分别为 l 1 , l 2 , … , l n l_1, l_2, …, l_n l1,l2,,ln个字符。我们希望将此段文本整齐打印在若干行上,每行最多 M M M个字符。“整齐”的标准是这样的。如果某行包含从第 i i i个到第 j ( i ≤ j ) j (i ≤ j) j(ij)个的单词,且单词之间的间隔为一个空格符,则行尾的剩余空格符数量为 M − j + i − ∑ k = i j l k M-j+i-\sum_{k=i}^{j}{l_k} Mj+ik=ijlk,此值必须为非负的,否则一行无法容纳这些单词。我们希望能最小化所有行的(除最后一行外)剩余空格数的立方之和。设计一个动态规划算法,在打印机上整齐打印一段 n n n个单词的文本。分析算法的时间和空间复杂度。
  
  
  根据题意,单个单词是不能跨行打印的。另外为简化分析,我们还需要假设任意一个单词 k k k的长度不超过一行所能容纳的字符个数,即 l k ≤ M , k = 1 , 2 , … , n l_k ≤ M,k = 1, 2, … , n lkMk=1,2,,n。对于任意一行来说,假设从单词 i i i开始,到单词 j j j结束,则该行末尾的剩余空格数为
  在这里插入图片描述
  我们用 l i n e _ c u b e s ( i , j ) line\_cubes(i, j) line_cubes(i,j)表示一行的剩余空格数的立方和,该行从单词 i i i开始,到单词 j j j结束。 l i n e _ c u b e s ( i , j ) line\_cubes(i, j) line_cubes(i,j)分三种情况:
  1) l i n e _ e x t r a ( i , j ) &lt; 0 line\_extra(i, j) &lt; 0 line_extra(i,j)<0:在这种情况下,一行容不下 i i i~ j j j的所有单词。显然,这种情况不能出现,所以把 l i n e _ c u b e s ( i , j ) line\_cubes(i, j) line_cubes(i,j)取为无穷大;
  2) l i n e _ e x t r a ( i , j ) ≥ 0 line\_extra(i, j) ≥ 0 line_extra(i,j)0 j = n j = n j=n:这意味着这是最后一行,由于最后一行不计算剩余空格数的立方,所以把 l i n e _ c u b e s ( i , j ) line\_cubes(i, j) line_cubes(i,j)取为 0 0 0
  3) l i n e _ e x t r a ( i , j ) ≥ 0 line\_extra(i, j) ≥ 0 line_extra(i,j)0 j &lt; n j &lt; n j<n:这意味着这不是最后一行,有 l i n e _ c u b e s ( i , j ) = ( l i n e _ e x t r a ( i , j ) ) 3 line\_cubes(i, j) = ( line\_extra(i, j) )^3 line_cubes(i,j)=(line_extra(i,j))3
  综上所述,可以得到
  在这里插入图片描述
  我们再定义只打印单词 1 1 1 ~ j j j的最优化方案的所有行的剩余空格数的立方和为 c u b e s ( j ) cubes(j) cubes(j)。这里需要补充说明一下:如果 j &lt; n j &lt; n j<n,那么 c u b e s ( j ) cubes(j) cubes(j)包括最后一行的剩余空格数的立方;如果 j = n j = n j=n,则 c u b e s ( j ) cubes(j) cubes(j)不计入最后一行。下面建立 c u b e s ( j ) cubes(j) cubes(j)的递归式。
  对于单词 1 1 1 ~ j j j的任意一个打印排列,单词 j j j自然位于最后一行的末尾,而最后一行的开始可以是1 ~ j j j中的任意一个单词。假设以单词 i ( 1 ≤ i ≤ j ) i (1 ≤ i ≤ j) i(1ij)作为最后一行的开始,那么这种情况下最后一行的剩余空格数的立方为 l i n e _ c u b e s ( i , j ) line\_cubes(i, j) line_cubes(i,j),而其余单词 1 1 1 ~ i − 1 i-1 i1的最优打印排列的所有行的剩余空格数的立方和为 c u b e s ( i − 1 ) cubes(i-1) cubes(i1)。将以上两项加起来,即可得单词 1 1 1 ~ j j j的所有行的剩余空格数的立方和,为 l i n e _ c u b e s ( i , j ) + c u b e s ( i − 1 ) line\_cubes(i, j) + cubes(i-1) line_cubes(i,j)+cubes(i1)。将 i i i 1 1 1 j j j进行遍历,寻找最小的 l i n e _ c u b e s ( i , j ) + c u b e s ( i − 1 ) line\_cubes(i, j) + cubes(i-1) line_cubes(i,j)+cubes(i1),作为单词 1 1 1 ~ j j j的最优打印排列的所有行的剩余空格数的立方和 c u b e s ( j ) cubes(j) cubes(j)。于是可以得到以下递归式
  在这里插入图片描述
  我们最终要计算的是 c u b e s ( n ) cubes(n) cubes(n)。可以用一个数组 p [ j ] p[j] p[j]来记录单词 1 1 1 ~ j j j的最优打印排列的最后一行的起始单词。
  在这里插入图片描述
  算法NEATLY-PRINT包含两个双层循环,以及一个单层循环,它的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
  本节相关的code链接。
  https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter15/Problems/Problem_15-4

  • 10
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值