9.6 训练参考

动态规划是算法竞赛的宠儿——几乎所有算法竞赛中都会出现动态规划的题目。本章虽然也包含一些知识点和理论讲解,但重中之重是那些经典题目(例如,LIS、LCS、最优矩阵链乘、树的重心和TSP等)和例题。本章的例题数量是本书目前为止最多的,难度也是最大的。建议读者先掌握不带星号的例题,然后逐步学习带一个星号的例题和两个星号的例题。有些例题比较复杂,甚至需要反复理解才能掌握。例题列表如表9-2所示。

表9-2 例题列表

 

  类别     题号     题目名称(英文)     备注  
  例题9-1     UVa1025     A Spy in the Metro     DAG的动态规划  
  例题9-2     UVa437     The Tower of Babylon     DAG的动态规划  
  例题9-3     UVa1347     Tour     经典问题  
  例题9-4     UVa116     Unidirectional TSP     多段图的最短路;字典序最小解  
  例题9-5     UVa12563     Jin Ge Jin Qu [h]ao     0-1背包问题  
  例题9-6     UVa11400     Lighting System Design     线性结构上的动态规划  
  例题9-7     UVa11584     Partitioning by Palindromes     线性结构上的动态规划;优化  
  例题9-8     UVa1625     Color Length     类似于LCS的动态规划;指标函数的分解  
  例题9-9     UVa10003     Cutting Sticks     类似于最优矩阵链乘的动态规划  
  例题9-10     UVa1626     Brackets Sequence     递归结构的动态规划  
  *例题9-11     UVa1331     Minimax Triangulation     类似于最优三角剖分的动态规划  
  例题9-12     UVa12186     Another Crisis     树形动态规划  
  例题9-13     UVa1220     Party at Hali-Bula     树形动态规划;解的唯一性  
  例题9-14     UVa1218     Perfect Service     树形动态规划;状态转移方程的优化  
  例题9-15     UVa10817     Headmaster's Headache     集合的动态规划;位运算  
  例题9-16     UVa1252     Twenty Questions     集合的动态规划;时间优化  
  *例题9-17     UVa1412     Fund Management     复杂状态的动态规划;和指标函数值有关的状态转移  
  例题9-18     UVa10618     Tango Tango Insurrection     多阶段决策问题  
  例题9-19     UVa1627     Team them up!     图论模型;0-1背包  
  例题9-20     UVa10934     Dropping water balloons     经典问题  
  例题9-21     UVa1336     Fixing the Great Wall     动态规划中“未来费用”的计算  
  例题9-22     UVa12105     Bigger is Better     用动态规划辅助其他算法  
  *例题9-23     UVa1204     Fun Game     字符串集合的动态规划  
  *例题9-24     UVa12099     Bookcase     类似0-1背包问题的动态规划;状态优化  
  *例题9-25     UVa12170     Easy Climb     最优解的特征分析;用单调队列优化动态规划  
  *例题9-26     UVa1380     A Scheduling Problem     树的动态规划(复杂)  
  **例题9-27     UVa10559     Blocks     给状态增加维度  
  *例题9-28     UVa1439     Exclusive Access 2     图论模型;Dilworth定理  
  **例题9-29     UVa1228     Integer Transmission     深入分析问题  
  **例题9-30     UVa1375     The Best Name for Your Baby     上下文无关文法;有“环”的动态规划  
  **例题9-31     UVa1628     Pizza Delivery     深入分析问题  

下面是一些形形色色的动态规划问题,难度各异。建议读者阅读所有题目,然后认真思考每一道题。对于能写出状态转移方程的题目,尽量编程提交。

习题9-1 最长的滑雪路径(Longest Run on a Snowboard, UVa 10285)

在一个R*CR,C≤100)的整数矩阵上找一条高度严格递减的最长路。起点任意,但每次只能沿着上下左右4个方向之一走一格,并且不能走出矩阵外。如图9-29所示,最长路就是按照高度25, 24, 23,…, 2, 1这样走,长度为25。矩阵中的数均为0~100。

图9-29 最长路径示例

习题9-2 免费糖果(Free Candies, UVa 10118)

桌上有4堆糖果,每堆有NN≤40)颗。佳佳有一个最多可以装5颗糖的小篮子。他每次选择一堆糖果,把最顶上的一颗拿到篮子里。如果篮子里有两颗颜色相同的糖果,佳佳就把它们从篮子里拿出来放到自己的口袋里。如果篮子满了而里面又没有相同颜色的糖果,游戏结束,口袋里的糖果就归他了。当然,如果佳佳足够聪明,他有可能把堆里的所有糖果都拿走。为了拿到尽量多的糖果,佳佳该怎么做呢?

习题9-3 切蛋糕(Cake Slicing, ACM/ICPC Nanjing 2007, UVa1629)

有一个nm列(1≤nm≤20)的网格蛋糕上有一些樱桃。每次可以用一刀沿着网格线把蛋糕切成两块,并且只能够直切不能拐弯。要求最后每一块蛋糕上恰好有一个樱桃,且切割线总长度最小。如图9-30所示是一种切割方法。

图9-30 蛋糕切法示例

习题9-4 串折叠(Folding, ACM/ICPC NEERC 2002, UVa1630)

给出一个由大写字母组成的长度为n(1≤n≤100)的串,“折叠”成一个尽量短的串。例如,AAAAAAAAAABABABCCD折叠成9(A)3(AB)CCD。折叠是可以嵌套的,例如,NEERCYESYESYESNEERCYESYESYES可以折叠成2(NEERC3(YES))。多解时可以输出任意解。

习题9-5 邮票和信封(Stamps and Envelope Size, ACM/ICPC World Finals 1995, UVa242)

假定一张信封最多贴5张邮票,如果只能贴1分和3分的邮票,可以组成面值1~13以及15,但不能组成面值14。我们说:对于邮票组合{1,3}以及数量上限S=5,最大连续邮资为13。1~13和15的组成方法如表9-3所示。

表9-3 1~3和15的组成方法

输入SS≤10)和若干邮票组合(邮票面值不超过100),选出最大连续邮资最大的一个组合。如果有多个并列,邮票组合中邮票的张数应最多。如果还有并列,邮票从大到小排序后字典序应最大。

习题9-6 电子人的基因(Cyborg Genes, UVa 10723)

输入两个A~Z组成的字符串(长度均不超过30),找一个最短的串,使得输入的两个串均是它的子序列(不一定连续出现)。你的程序还应统计长度最短的串的个数。例如,ABAAXGF和AABXFGA的最优解之一为AABAAXGFGA,一共有9个解。

习题9-7 密码锁(Locker, Tianjin 2012, UVa1631)

有一个nn≤1000)位密码锁,每位都是0~9,可以循环旋转。每次可以让1~3个相邻数字同时往上或者往下转一格。例如,567890->567901(最后3位向上转)。输入初始状态和终止状态(长度不超过1000),问最少要转几次。例如,111111到222222至少转2次,由896521到183995则要转12次。

习题9-8 阿里巴巴(Alibaba, ACM/ICPC SEERC 2004, UVa1632)

直线上有nn≤10000)个点,其中第i个点的坐标是xi,且它会在di秒之后消失。Alibaba可以从任意位置出发,求访问完所有点的最短时间。无解输出No solution。

习题9-9 仓库守卫(Storage Keepers, UVa10163)

你有nn≤100)个相同的仓库。有mm≤30)个人应聘守卫,第i个应聘者的能力值为Pi(1≤Pi≤1000)。每个仓库只能有一个守卫,但一个守卫可以看守多个仓库。如果应聘者i看守k个仓库,则每个仓库的安全系数为Pi/K的整数部分。没人看守的仓库安全系数为0。

你的任务是招聘一些守卫,使得所有仓库的最小安全系数最大,在此前提下守卫的能力值总和(这个值等于你所需支付的工资总和)应最小。

习题9-10 照亮体育馆(Barisal Stadium, UVa10641)

输入一个凸n(3≤n≤30)边形体育馆和多边形外的m(1≤m≤1000)个点光源,每个点光源都有一个费用值。选择一组点光源,照亮整个多边形,使得费用值总和尽量小。如图9-31所示,多边形ABCDEF可以被两组光源{1,2,3}和{4,5,6}照亮。光源的费用决定了哪组解更优。

图9-31 被点光源照亮的多边形

习题9-11 禁止的回文子串(Dyslexic Gollum, ACM/ICPC Amritapuri 2012, UVa1633)

输入正整数nk(1≤n≤400,1≤k≤10),求长度为n的01串中有多少个不含长度至少为k的回文连续子串。例如,n=k=3时只有4个串满足条件:001, 011, 100, 110。

习题9-12 保卫Zonk(Protecting Zonk, ACM/ICPC Dhaka 2006, UVa12093)

给定一个有nn≤10000)个结点的无根树。有两种装置A和B,每种都有无限多个。

 

求覆盖所有边的最小花费。

习题9-13 叠盘子(Stacking Plates, ACM/ICPC World Finals 2012, UVa1289)

n(1≤n≤50)堆盘子,第i堆盘子有hi个盘子(1≤hi≤50),从上到下直径不减。所有盘子的直径均不超过10000。有如下两种操作。

 

你的任务是用最少的操作把所有盘子叠成一堆。

习题9-14 圆和多边形(Telescope, ACM/ICPC Tsukuba 2000, UVa1543)

给你一个圆和圆周上的n(3≤n≤40)个不同点。请选择其中的m(3≤mn)个,按照在圆周上的顺序连成一个m边形,使得它的面积最大。例如,在图9-32中,右上方的多边形最大。

图9-32 圆和多边形问题示意图

习题9-15 学习向量(Learning Vector, ACM/ICPC Dhaka 2012, UVa12589)

输入n个向量(x,y)(0≤xy≤50),要求选出k个,从(0,0)开始画,使得画出来的折线与x轴围成的图形面积最大。例如,4个向量是(3,5), (0,2), (2,2), (3,0),可以依次画(2,2), (3,0), (3,5),围成的面积是21.5,如图9-33所示。输出最大面积的两倍。1≤kn≤50。

习题9-16 野餐(The Picnic, ACM/ICPC NWERC 2002, UVa1634)

输入mm≤100)个点,选出其中若干个点,以这些点为顶点组成一个面积最大的凸多边形,使得内部没有输入点(边界上可以有)。输入点的坐标各不相同,且至少有3个点不共线,如图9-34所示。

 

  图9-33 向量所围面积     图9-34 输入点  

习题9-17 佳佳的筷子(Chopsticks, UVa 10271)

中国人吃饭喜欢用筷子。佳佳与常人不同,他的一套筷子有3只,两根短筷子和一只比较长的(一般用来穿香肠之类的食物)。两只较短的筷子的长度应该尽可能接近,但是最长那只的长度无须考虑。如果一套筷子的长度分别是ABCABC),则用(A-B)2的值表示这套筷子的质量,这个值越小,这套筷子的质量越高。

佳佳请朋友吃饭,并准备为每人准备一套这种特殊的筷子。佳佳有NN≤1000)只筷子,他希望找到一种办法搭配好K+8套筷子,使得这些筷子的质量值和最小。保证筷子足够,即3K+24≤N

提示:需要证明一个猜想。

习题9-18 棒球投手(Pitcher Rotation, ACM/ICPC Kaosiung 2006, UVa1379)

你经营着一支棒球队。在接下来的g+10天中会有g(3≤g≤200)场比赛,其中每天最多一场比赛。你已经分析出你的n(5≤n≤100)个投手中每个人对阵所有m(3≤m≤30)个对手的胜率(一个n*m矩阵),要求给出作战计划(即每天使用哪个投手),使得总获胜场数的期望值最大。注意,一个投手在上场一次后至少要休息4天。

提示:如果直接记录前4天中每天上场的投手编号1~n,时间和空间都无法承受。

习题9-19 花环(Garlands, ACM/ICPC CERC 2009, UVa1443)

你的任务是用nn≤40000)条等长细绳组成一个花环。每条细绳上都有一颗珍珠,重量为wi(1≤wi≤10000)。花环应由m(2≤m≤10000)个片段组成,每个片段必须包含连续的偶数条细绳。每个片段的一半称为“半段”(两个半段包含相同数量的细绳),每个“半段”最多能有d(1≤d≤10000)条细绳。你的任务是让最重的半段尽量轻。如图9-35所示,12条细绳的最优解是如下的3个片段,最重的半段的重量为6(左数第1, 4, 6个半段)。

图9-35 12条细绳的最优解

习题9-20 山路(Mountain Road, NWERC 2009, UVa12222)

有一条狭窄的山路只有一个车道,因此不能有两辆相反方向的车同时驶入。另外,为了确保安全,对于山路上的任意一点,相邻的两辆同向行驶的车通过它的时间间隔不能少于10秒。给定n(1≤n≤200)辆车的行驶方向、到达时刻(对于往右开的车来说是到达山路左端点的时刻,而对于往左开的车来说是指到达右端点的时刻),以及行驶完山路的最短时间(为了保证安全,实际行驶时间可以高于这个值),输出最后一辆车离开山路的最早时刻。输入保证任意两辆车的到达时刻均不相同。

提示:本题的主算法并不难,但是实现细节需要仔细推敲。

习题9-21 周期(Period, ACM/ICPC Seoul 2006, UVa1371)

两个串的编辑距离为进行的修改、删除和插入操作次数的最小值(每次一个字符)。如图9-36所示,A=abcdefg和B=ahcefig的编辑距离为3。

图9-36 编辑距离

如果x可以分成若干部分,使得每部分和y的编辑距离都不超过k,则yxk-近似周期。例如,x=abcdabcabb,y=abc,x可以分解为abcd+abc+abb,3部分和y的编辑距离分别为1, 0, 1,因此yx的1-近似周期。

输入由小写字母组成的xy,求最小的k使得yxk-近似周期。|y|≤50,|x|≤5000。

提示:直接想出的动态规划算法很可能太慢,要想办法降低时间复杂度。

习题9-22 俄罗斯套娃(Matryoshka, ACM/ICPC World Finals 2013, UVa 1579)

桌上有nn≤500)个套娃排成一行,你的任务是把它们套成若干个套娃组,使得每个套娃组内的套娃编号恰好是从1开始的连续编号。操作规则如下:

 

执行合并操作的前后,所有套娃都是关闭的。为了合并两个套娃组,你需要交替地把一些套娃打开、重新套起来、关闭。例如,为了合并[1, 2, 6]和[4],需要打开套娃6和4;为了合并[1, 2, 5]和[3, 4],需要打开套娃5, 4, 3(只有先打开4才能打开3)。要求打开/关闭的总次数最少。无解输出impossible。例如,“1 2 3 2 4 1 3”需要打开7次,如表9-4所示。

表9-4 “1 2 3 2 4 1 3”需打开7次

 

  操作前     操作后     打开的套娃  
  1 2 3 2 4 1 3     [1 2] 3 2 4 1 3     2  
  [1 2] 3 2 4 1 3     [1 2 3] 2 4 1 3     3  
  [1 2 3] 2 4 1 3     [1 2 3] [2 4] 1 3     4  
  [1 2 3] [2 4] 1 3     [1 2 3] [2 4 1] 3     4, 2  
  [1 2 3] [2 4 1] 3     [1 2 3] [2 4 1 3]     4, 3  

习题9-23 优化最大值电路(Minimizing Maximizer, ACM/ICPC CERC 2003, UVa1322)

所谓Maximizer,就是一个n输入1输出的硬件电路,它可以用若干个串行Sorter来实现,其中每个Sorter(i,j)表示把第ij个输入从小到大排序。最后一个Sorter的第n个输出就是整个Maximizer的输出。输入一个由m个Sorter组成的Maximizer,保留尽量少的Sorter(顺序不变),使得Maximizer仍能正常工作。n≤50000,m≤500000。

————————————————————

(1) 注意这个函数的工作方式并不像它表面显示的那样——如果把-1改成-2,并不是在把所有d值都初始化为-2!请只用0和-1作为“批量赋值”的参数。

(2) 输出的最后会有一个多余空格,并且没有回车符。在使用时,应在主程序调用print_ans后加一个回车符。如果比赛明确规定行末不允许有多余空格,则可以像前面介绍的那样加一个变量first来帮助判断。

(3)  如果状态比较复杂,推荐用STL中的map而不是普通数组保存状态值。这样,判断状态S是否算过只需用if(d.count(S))即可。

(4) 第二个人走到i+1时本应转移到d(i,i+1),但是根据此处规定,必须写成d(i+1,i)。

(5) 还有《劲歌金曲2》和《劲歌金曲3》,但本题不予考虑。

(6) 显然大多数歌的长度都大于3分钟,但是KTV可以“切歌”,因此这里的“长度”实际上是指“想唱的时间长度”。

(7) 判断回文也可以用动态规划,读者不妨一试。

(8) 虽然思路很清晰,但具体实现还需要斟酌,建议读者独立完成。

(9) 如何判断i-j是否为多边形的对角线?限于篇幅,本书没有对计算几何进行专门讨论,请读者参考《算法竞赛入门经典——训练指南》的几何部分。

(10) 所谓NPC,即NP-完全问题(NP-Complete Problem),是指一类目前还没有找到多项式算法的问题。它的确切定义超出了本书的范围。

(11) 完整实现见代码仓库。

(12) 其实还有一个更简单的做法,既不需要高精度,也不需要“反着想”,参见代码仓库。

(13) 本题的解法看上去比较常规,但是在NWERC这样较高水平的比赛中,却没有队伍做出来。

(14) 证明思路是从定向方案构造分层图。先把所有路径的起点作为第0层。

(15) 准确地说这不是动态规划,而是组合数学中的递推,因为本题不是最优化问题,而是计数问题。不过解决两个问题的思路是相同的,所以很多人把组合数学中的递推也算作动态规划。

(16) 本题在实现上有一些细节需要注意,建议参考代码仓库。