收藏 分享(赏)

动态规划的深入探讨.doc

上传人:lxhqcj 文档编号:6425879 上传时间:2019-04-12 格式:DOC 页数:37 大小:266.50KB
下载 相关 举报
动态规划的深入探讨.doc_第1页
第1页 / 共37页
动态规划的深入探讨.doc_第2页
第2页 / 共37页
动态规划的深入探讨.doc_第3页
第3页 / 共37页
动态规划的深入探讨.doc_第4页
第4页 / 共37页
动态规划的深入探讨.doc_第5页
第5页 / 共37页
点击查看更多>>
资源描述

1、IOI99 中国集训队优秀论文选 - 79 -把握本质,灵活运用动态规划的深入探讨【关键字】 动态规划 构思 实现【摘要】 本文讨论了动态规划这一思想的核心内容和其基本特点,探讨了动态规划思想的适用范围,动态规划子问题空间和递推关系式确立的一般思路。通过例子说明在子问题确立过程中的一些问题的解决办法:通过加强命题或适当调节确定状态的变量等手段帮助建立动态规划方程,通过预处理使动态规划的过程容易实现等。接着,分析动态规划实现中可能出现的空间溢出问题及一些解决办法。总结指出,动态规划这一思想,关键还在于对不同的问题建立有效的数学模型,在把握本质的基础上灵活运用。一、引言动态规划是一种重要的程序设计

2、思想,具有广泛的应用价值。使用动态规划思想来设计算法,对于不少问题往往具有高时效,因而,对于能够使用动态规划思想来解决的问题,使用动态规划是比较明智的选择。能够用动态规划解决的问题,往往是最优化问题,且问题的最优解(或特定解)的局部往往是局部问题在相应条件下的最优解,而且问题的最优解与其子问题的最优解要有一定的关联,要能建立递推关系。如果这种关系难以建立,即问题的特定解不仅依赖于子问题的特定解,而且与子问题的一般解相关,那么,一方面难以记录下那么多的“一般解” ,另一方面,递推的效率也将是很低的;此外,为了体现动态规划的高时效,子问题应当是互相重叠的,即很多不同的问题共享相同的子问题。(如果子

3、问题不重叠,则宜使用其它方法,如分治法等。)动态规划一般可以通过两种手段比较高效地实现,其一是通过自顶向下记忆化的方法,即通过递归或不递归的手段,将对问题最优解的求解,归结为求其子问题的最优解,并将计算过的结果记录下来,从而实现结果的共享;另一种手段,也就是最主要的手段,通过自底向上的递推的方式,由于这种方式代价要比前一种方式小,因而被普遍采用,下面的讨论均采用这种方式实现。动态规划之所以具有高时效,是因为它在将问题规模不断减小的同时,有效地把解记录下来,从而避免了反复解同一个子问题的现象,因而只要运用得当,较之搜索而言,效率就会有很大的提高。把握本质,灵活运用动态规划的深入探讨- 80 -

4、IOI99 中国集训队优秀论文选动态规划的思想,为我们解决与重叠子问题相关的最优化问题提供了一个思考方向:通过迭代考虑子问题,将问题规模减小而最终解决问题。适于用动态规划解决的问题,是十分广泛的。动态规划的思想本身是重要的,但更重要的是面对具体问题的具体分析。要分析问题是否具备使用动态规划的条件,确定使用动态规划解题的子问题空间和递推关系式等,以及在(常规)内存有限的计算机上实现这些算法。下面分别就构思和实现两个方面进一步探讨动态规划这一思想。二、动态规划解题的构思当我们面对一个问题考虑用动态规划时,十分重要的一点就是判断这个问题能否用动态规划高效地解决。用动态规划构思算法时,往往要考虑到这个

5、问题所涉及到的子问题(子问题空间),以及如何建立递推式,并最终实现算法。其实,这些过程往往是交织在一起的,子问题空间与递推关系本身就是紧密相联的,为了有效地建立起递推关系,有时就要调整子问题空间;而根据大致确定的子问题空间又可以启发我们建立递推关系式。而能否最终用一个递推关系式来联系问题与其子问题又成了判断一个问题能否使用动态规划思想解决的主要依据。因而孤立地来看这其中的每一部分,硬把思考过程人为地分成几个部分,是困难的,也是不必要的。而且动态规划这种思想方法,没有固定的数学模型,要因题而异,因而也就不可能归纳出一种“万能”的方法。但是对大多数问题而言,还是能够有一个基本的思考方向的。首先,要

6、大致分析一个问题是否可能用动态规划解决。如果一个问题难以确定子问题,或问题与其子问题的特殊解之间毫无关系,就要考虑使用其它方法来解决( 如搜索或其它方法等 )。做一个大概的判断是有必要的,可以防止在这上面白花时间。通常一个可以有效使用动态规划解决的问题基本上满足以下几方面的特性:1、 子问题的最优解仅与起点和终点(或有相应代表意义的量)有关而与到达起点、终点的路径无关。2、 大量子问题是重叠的,否则难以体现动态规划的优越性。下面以 IOI97 的“字符识别 ”问题为例进行分析一般情况下动态规划思路的建立。IOI97 的字符识别问题,题目大意是:在 FONT.DAT 中是对(空格)、把握本质,灵

7、活运用动态规划的深入探讨IOI99 中国集训队优秀论文选 - 81 -AZ 这 27 个符号的字形说明。对每一个符号的字符点阵,用 20 行每行 20 个“0”或者“1”表示。在另一个输入文件中,描述了一串字符的点阵图象(共 N行),但字符可能是“破损的” ,即有些 0 变成了 1,而有些 1 变成了 0。每行固定也为 20 个“0”或“1” ,但每一个字符对应的行可能出现如下情形: 仍为 20 行,此时没有丢失的行也没有被复制的行; 为 19 行,此时有一行被丢失了; 为 21 行,此时有一行被复制了,复制两行可能出现不同的破损。要求输出,在一个假定的行的分割情况下,使得“0”与“1”的反相

8、最少的方案所对应的识别结果(字符串)。在初步确定这个问题可以用动态规划思想解决之后,我认为可以考虑用数学的方法( 或观点 )来刻划这个问题,比如通常的最优化问题(这也是动态规划解决的主要问题) ,总会有一个最优化的标准,动态规划要通过递推来实现,就要求分析确定这个状态所需要的量。比如字符识别问题,在问题规模下相当于求N 行的一种分割与对应方法,因而很自然地,考虑前几行就成了一个确定状态的量。最优的标准题中已经给出,即在某种假设(包括分割方法与对应识别方法 )下,使得“0”与“1”反相数最少。如果把这个度量标准看作一个函数,这实际上就是一个最优化函数(指标函数),最优化函数的值依赖于自变量,即确

9、定状态的量。自变量的个数(这里是一个,即行数,考虑前几行之意 ),要因题而异,关键是要有效地确定状态,在这种状态下,因保证靠这些量已经能够确定最优化函数的值,即最优化函数在这些量确定的时候理论上应有确定的值,否则量是不够的或要使用其它量来刻划,而即使能够完全确定,但在建立递推关系式时发生困难,也要根据困难相应调整确定最优化函数值的自变量。而反过来,如果设定了过多的量来确定最优化函数值,那么,动态规划的效率将会大大下降,或者解了许多不必要解的子问题,或者将重叠子问题变成了在这种自变量条件下的非重叠子问题,从而大大降低效率,甚至完全失去动态规划的高效。在这个例子中,对于前 L 行,此最优化函数显然

10、有确定的值。动态规划的递推的一种重要思想是将复杂的问题分解为其子问题。因而确定子问题空间及建立递推关系式是十分重要的。根据确定最优化函数值的自变量,往往对子问题空间有着暗示的作用。通常,通过对最接近问题的这步进行倒推,可以得到这个问题规模减小一些的子问题,不断这样迭代考虑,就往往能够体会到问题的子问题空间。而在这个过程中,通过这种倒推分析,也比较容易得出这种递推关系。需要指出,这仅仅是对一些题目解题思考过程的总结,不同的题目原则上仍应区别对待。比如字符识别问题,考虑 n 行该最优化函数把握本质,灵活运用动态规划的深入探讨- 82 - IOI99 中国集训队优秀论文选值时,注意到最终一定是按照字

11、符分割与识别的,因而最后一个字符或者是 19行,或者是 20 行,再或者是 21 行,仅这样三种可能情况,依次考虑这三种分割方法,对于切割下来的这一段对应于一个字符,对于每一种切割方案,当然应该选择最匹配的字符(否则,如果不使用反相情况最少的字符作为匹配结果而导致全局的最优,那么只要在这一步换成反相情况最少的字符,就得到比假定的“最优”更优的结果,从而导致矛盾)。在去除一个字符后,行数有所减少,而这些行去匹配字符显然也应当使用最优的匹配(可以用反证法证明,与前述类似),于是得到一个与原问题相似(同确定变量,同最优化标准)但规模较小的子问题,与此同时子问题与原问题的递推关系事实上也得到了建立:f

12、i:=minCompare19i-19+1+fi-19,Compare20i-20+1+fi-20, Compare21i-21+1+fi-21fi表示对前 i 行进行匹配的最优化函数值;Compare19i、Compare20i、Compare21i 分别表示从 i 行开始的 19 行、20 行、21 行与这三种匹配方式下最接近的字符的反相的“0”与“1”的个数。初始情况,f0=0,对于不可能匹配的行数,用一个特殊的大数表示即可。当然,本题的问题主要还不在于动态规划的基本思考上(这里只是通过这个例子,讲一下对于不少动态规划问题的一种基本的思考方向),还有数学建模 (用 2 进制表示 0、1

13、串) 等( 源程序见附录中的程序 1)。有时虽然按上述思路得出的确定状态的量已经能够使最优化函数具有确定的值,但是在建立递推关系时发生困难,通过引入新的变量或调整已有变量,也是一条克服困难的途径。比如,NOI97 的一题“积木游戏 ”,题目大意是:积木是一个长方体,已知 N 个有编号的积木的三边 (a、b、c 边)长,要求出用 N 块中的若干块堆成 M(1MN100)堆,使总高度最大的高度值,且满足: 第 K 堆中任意一块的编号大于第 K+1 堆中任意一块积木的编号; 任意相邻两块,下面的块的上表面要能包含上面的那块的下表面,且下面的块的编号要小于上面积木的编号。因为题目要求编号小的堆的积木编

14、号较大,这不太自然,在不改变结果的前提下,把题目改作编号小的堆的积木编号较小,这显然不会影响到最终的高度和,而且,此时每一种合理的堆放方法可看作,按编号递增的顺序选择若干积木,按堆编号递增的顺序逐堆放置,每堆中积木依次在前一个上面堆放而最终形成一种堆放方案。使用上面一般的分析方法,很容易看出,考虑前 i 个木块放置成前 j 堆,这样,i、j 两个量显然能够确定最优函数的值,然而递推关系把握本质,灵活运用动态规划的深入探讨IOI99 中国集训队优秀论文选 - 83 -却不易直接建立,稍作分析就会发现,问题主要出在第 i 块到底能否堆放到其子问题(i-1,j 作变量确定的状态)的最优解方案的最后一

15、堆上。如果考虑增加该序列最后一块的顶部的长与宽的(最小)限制这两个变量,建立递推关系并不困难,然而,很明显,递推过程中大量结果并未被用到,这就人为地扩大了子问题空间,不仅给存储带来麻烦,而且效率也很低。其实,建立递推需要的仅仅是在子问题解最后一堆顶部能否容纳当前积木块,而题中可能产生的这种限制性的面最多仅有 3*100+1(无限制)=301 种情况,这样在多引入一个“最后一堆顶部能够容纳下第 k 种面的要求”这个量后,递推关系只要分当前块另起一堆、当前块加在前一堆上(如果可能的话)和当前块不使用这三种情况就可以了。(源程序参见所附程序 2)此外,有些问题可能会出现仅靠这种调整递推关系仍难以建立

16、,这时,通过增加其它量或函数来建立递推关系式也是一种思考方向(类似于数学归纳法证明时的“加强命题”)。因为,用动态规划解题的一个重要特征是通过递推,而递推是利用原有结果得到新结果的过程。如果在理论上可以证明,一个难以直接实现递推的问题可以通过引入新的递推关系,同时将两者解决,这看起来把问题复杂化了,而实际上由于对于每一步递推,在增加了解决的问题的同时也增加了条件(以前解决的值) ,反而使递推容易进行。举例说明,IOI98 中的“多边形”一题,大意如下:有一个多边形(N 边形) ,顶点上放整数,边上放 “+”或“*” ,要寻找一种逐次运算合并的顺序,通过 N-1 次运算,使最后结果最大。如果单纯

17、考虑用 MAXI,L,从 I 开始进行 L 个运算所得的最大值,则难以实现递推,而根据数学知识,引入了 MINI,L为从 I 开始进行 L 个运算所得的最小值,在进行递推时,却能够有效地用较小的 I,L 来得到较大时的结果,从而事实上同时解决了最小值与最大值两个问题。递推关系式如下:(考虑 I 从 1 到 N,L 从 1 到 N-1)考虑 t(最后一步运算位置)从 0 到 L-1:如果最后一步运算为“+”则:min(i,L)=最小值min(i,t)+min(i+t+1-1) mod N+1,L-t-1)max(i,L)=最大值max(i,t)+max(i+t+1-1) mod N+1,L-t-

18、1)如果最后一步运算为“*”则:min(i,L)=最小值min(i,t)*min(i+t+1-1) mod N+1,L-t-1),min(i,t)*max(i+t+1-1) mod N+1,L-t-1),max(i,t)*min(i+t+1-1) mod N+1,L-t-1),把握本质,灵活运用动态规划的深入探讨- 84 - IOI99 中国集训队优秀论文选max(i,t)*max(i+t+1-1) mod N+1,L-t-1)max(i,L)=最大值min(i,t)*min(i+t+1-1) mod N+1,L-t-1),min(i,t)*max(i+t+1-1) mod N+1,L-T-1

19、)max(i,t)*min(i+t+1-1) mod N+1,L-t-1),max(i,t)*max(i+t+1-1) mod N+1,L-t-1)(源程序见附录中的程序 3)此外,动态规划通过递推来实现,因而问题与子问题越相似,越有规律就越容易进行操作。因而对于某些自身的阶段和规律不怎么明显的问题,可以通过一个预处理,使其变得更整齐,更易于实现。例如,ACM97 亚洲赛区/上海区竞赛一题“正则表达式(Regular Expression) 的匹配 ”问题,题目大意是:正则表达式是含有通配符的表达式,题目定义的广义符有: . 表示任何字符 c1-c2 表示字符 c1 与 c2 间的任一字符 c

20、1-c2 表示不在字符 c1 与 c2 间的任一字符 * 表示它前面的字符可出现 0 或多次 + 表示它前面的字符可出现一次或多次 表示它后面的字符以一个一般字符对待。对一个输入串,寻找最左边的与正则表达式匹配的串(相同条件下要最长的)。这里如果不作预处理,则有时一个广义符可对应多个字符,有时又是多个广义符仅对应一个字符,给系统化处理带来很多麻烦。因而有必要对正则表达式进行标准化,使得或者某个结点仅对应一个字符,或者用一特殊标记表明它可以重复多次。定义记录类型:NodeType=RecordStartChar: Char; 开始字符EndChar: Char; 结束字符Belong: Bool

21、ean 是否属于Times: Boolean; False: 必须一次; True:可以多次,也可以不出现End;对输入数据预处理之后,建立递推关系就不太困难了。用 Proi,j表示前 i个正则表达式结点对以第 j 个字符为终点的子串的匹配情况 (True/False),对于为 True 的情况,同时指明此条件下最先的开始位置。如果第 i 个正则表达式结点是仅出现一次的,那么,如果它与第 j 个字符不匹配,则该值为 False,否则,它与 Proi-1,j-1相同。(初始时 Pro0,x=True)。如果它是可重复多次的,那么它把握本质,灵活运用动态规划的深入探讨IOI99 中国集训队优秀论文

22、选 - 85 -可以被解释成 0 个或多个字符。在它自身与相应位置的 0 个或多个字符匹配的条件下依次考虑这些可能情况,只要其中含 True,则 Proi,j为 True,同时记录下这些达到 True 的情况中起点最先的。按此递推,直到 i 达到结点个数。(源程序见所附程序 4)三、动态规划实现中的问题动态规划解决问题在有了基本的思路之后,一般来说,算法实现是比较好考虑的,但有时也会遇到一些问题,而使算法难以实现。动态规划思想设计的算法从整体上来看基本都是按照得出的递推关系式进行递推,这种递推,相对于计算机来说,只要设计得当,效率往往是比较高的,这样在时间上溢出的可能性不大,而相反地,动态规划

23、需要很大的空间以存储中间产生的结果,这样可以使包含同一个子问题的所有问题共用一个子问题解,从而体现动态规划的优越性,但这是以牺牲空间为代价的,为了有效地访问已有结果,数据也不易压缩存储,因而空间矛盾是比较突出的。另一方面,动态规划的高时效性往往要通过大的测试数据体现出来(以与搜索作比较),因而,对于大规模的问题如何在基本不影响运行速度的条件下,解决空间溢出的问题,是动态规划解决问题时一个普遍会遇到的问题。对于这个问题,我认为,可以考虑从以下一些方面去尝试:一个思考方向是尽可能少占用空间。如从结点的数据结构上考虑,仅仅存储必不可少的内容,以及数据存储范围上精打细算(按位存储、压缩存储等 )。当然

24、这要因题而异,进行分析。另外,在实现动态规划时,一个我们经常采用的方法是用一个与结点数一样多的数组来存储每一步的决策,这对于倒推求得一种实现最优解的方法是十分方便的,而且处理速度也有一些提高。但是在内存空间紧张的情况下,我们就应该抓住问题的主要矛盾。省去这个存储决策的数组,而改成在从最优解逐级倒推时,再计算一次,选择某个可能达到这个值的上一阶段的状态,直到推出结果为止。这样做,在程序编写上比上一种做法稍微多花一点时间,运行的时效也可能会有一些(但往往很小 )的下降,但却换来了很多的空间。因而这种思想在处理某些问题时,是很有意义的。但有时,即使采用这样的方法也会发现空间溢出的问题。这时就要分析,

25、这些保留下来的数据是否有必要同时存在于内存之中。因为有很多问题,动态规划递推在处理后面的内容时,前面比较远处的内容实际上是用不着的。对于这类问题,在已经确信不会再被使用的数据上覆盖数据,从而使空间得以重复利用,如果能有效地使用这一手段,对于相当大规模的问题,空间也不至于溢出。(为了求出最优方案,保留每一步的决策仍是必要的,这同样需要空间。把握本质,灵活运用动态规划的深入探讨- 86 - IOI99 中国集训队优秀论文选)一般地说,这种方法可以通过两种思路来实现。一种是递推结果仅使用Data1 和 Data2 这样两个数组,每次将 Data1 作为上一阶段,推得 Data2 数组,然后,将 Da

26、ta2 通过复制覆盖到 Data1 之上,如此反复,即可推得最终结果。这种做法有一个局限性,就是对于递推与前面若干阶段相关的问题,这种做法就比较麻烦;而且,每递推一级,就需要复制很多的内容,与前面多个阶段相关的问题影响更大。另外一种实现方法是,对于一个可能与上 N 阶段相关的问题,建立数组 Data0N,其中各项即为与原 Data1/Data2 相同的内容。这样不采用这种内存节约方式时对于下标 K 的访问只要对应成对下标 K mod (N+1)的访问,就可以了。与不作这种处理的方法相比,对于程序修改的代码很少,速度几乎不受影响(用电脑做 MOD 运算是很快的),而且需要保留不同的阶段数也都能很

27、容易实现。这种手段对不少题目都适用,比如:NOI98 的“免费馅饼”,题目大意是:有一个舞台,宽度 W 格(1 W 99 的奇数),高度 H 格(1H100),游戏者在时刻 0 时位于舞台正中,每个单位时间可以从当时位置向左移 2 格、向左移 1 格、保持不动、向右移 1 格或者向右移 2 格,每个馅饼会告知初始下落的时间和位置以及下落速度(1 秒内下移的格子数)和分值。仅在某 1 秒末与游戏者位于同一格内的馅饼才被认为是接住的。求一种移动方案,使得分最大。注意:馅饼已按初始下落时间排序。从问题来看,想到动态规划并不是很困难的。但是,题中规定初始下落时间从 0 到 1000,而且考虑下落到最后

28、可能时间要到 1100 左右,而宽度可达 99,以时间- 位置作为状态决定因素进行递推,速度不会慢,但如果采用初始数据经预处理后的结果( 即在何时到何地可得多少分的描述数组)用一个数组,动态规划递推用一个数组,记录每步决策用一个数组,因得分题中未指出可能的大小,如果采用前两个 Longint 型,最后一个 Shortint 型,所须内存约为 1100*99*9 字节,即约 957KB,这显然是不可能存得下的。但是注意到在进行递推时,一旦某一个( 时间,位置) 对应的最大分值一确定,这个位置的原始数据就不再有用,因而两者可以合二为一,从而只要 1100*99*5 字节,即约 532KB。这样对于

29、题目规模的问题就勉强可以解决了。 当然,如果更进一步思考,其实这个问题中递推是仅与上一个时间有关的,而馅饼实际上仅使用了当前位置的值。由于初始下落时间已经排序,那么当读到初始下落时间晚于当前处理时间时,就不必马上读入。为了避免重复和无规律地读盘和内存开销过大,只要记录下当前之后约 100 个时间单位内的情况就可以了,使用前面所说的循环使用内存的方法,只要 101*99*4+99*2*2=40392 字节,不到 40KB,而对于每一个时间仅需 99 个shortint 存储决策即可,就算把问题规模提高到 3000 或者 4000 个时间单位也能顺把握本质,灵活运用动态规划的深入探讨IOI99 中

30、国集训队优秀论文选 - 87 -利出解。 (源程序见附录中的程序 5) 当采用以上方法仍无法解决内存问题时,也可以采用对内存的动态申请来使绝大多数测试点能有效出解(而且,使用动态内存还有一点好处,就是在重复使用内存而进行交换时,可以只对指针进行交换,而不复制数据),这在竞赛中也是十分有效的。 四、总结动态规划是一种重要的程序设计思想。但是,由于它没有确定的算法形式,因而也就有较大的灵活性,但它的本质却具有高度的相似性。所以,学习和使用这一思想方法,关键在于在理解和把握其本质的基础上灵活运用。本文虽然谈到了一些思想方法,但这些仅是对一些较普遍问题的讨论,针对具体问题进行具体分析建立数学模型才是最

31、重要而关键之处。【参考资料】1、吴文虎、王建德 实用算法的分析与程序设计电子工业出版社 ISBN 7-5053-4402-1/TP.20362、吴文虎、王建德 青少年国际和全国信息学( 计算机)奥林匹克竞赛指导组合数学的算法与程序设计清华大学出版社ISBN 7-302-02203-8/TP.10603、 NOI97、NOI98、IOI97 、IOI98 试题, ACM97 亚洲赛区试题【程序】程序 1 IOI97 字符识别“字符识别”的基本动态规划方程已在正文中说明,这里补充说明一下本题提高速度的关键错位比较时提高效率。注意到少一行与多一行时的比较,虽然可能出现错位,但每一行仅有与邻近的两行比

32、较的可能,先把可能的比较记录下来,再累计从端点到某一位置的非错位时反相数之和与错位时反相数之和,把握本质,灵活运用动态规划的深入探讨- 88 - IOI99 中国集训队优秀论文选考虑 20 种情况,仅需一重循环 (不考虑比较一行的子程序内的循环)即可,效率得到很大提高program Character_Recognition; “字符识别”程序constcc:array 127 of char=( ,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z); 字符常量varf,f1,f2:text; 文件变量font:array 1540 of

33、longint; 记录字形的数组,一个 longint 数表示 20 位 2 进制数,下同dd:array 11200 of longint; 待分析的点阵数据str:string; 读入的串i,j,k:integer; 辅助变量t:word; ff:integer;bin:array 120 of longint; 2 的幂pro:array 01200 of word; 动态规划数组sta:array 01200 of byte; 每步分析的最优字符序号bf:array 01200 of word; 每步分析的上一个字符的终点pf:array 121,01 of word; 错位比较时用n

34、:integer;procedure getnum(var l:longint); String-longint 转换vari:integer;beginl:=0;for i:=1 to 20 doif stri=1 then inc(l,bini);end;function compare0(a,b:longint):byte; 比较 a 表示的行与 b 表示的行的反相个数vark:byte;i:integer;begina:=a xor b;k:=0;for i:=1 to 20 doif a and binilongint 转换end;fillchar(pro,sizeof(pro),2

35、55); 初值 65535fillchar(sta,sizeof(sta),0); 每步分析出的最优字符 fillchar(bf,sizeof(bf),255); 每步分析出的最优切割pro0:=0;sta0:=0;bf0:=0;for i:=19 to n do 考虑 19 行至 n 行beginif (i=19) and (proi-1965535) then 如果切去一个 20 行字符后的情况可能begint:=compare20(i-20+1,ff); 比较从 i-20+1 起 20 行与标准结果最接近的结果与差别if t+proi-20=21) and (proi-21aai,k t

36、henbegint:=aai,j;aai,j:=aai,k;aai,k:=tend;end;function add(a1,a2:integer):integer; 在面标记中增添当前面,并返回相应的序号vari,j:integer;beginfor i:=1 to num doif (a1=sizei,1) and (a2=sizei,2) then begin add:=i; exit end;inc(num);sizenum,1:=a1;sizenum,2:=a2;add:=num;end;procedure preprocess; 预处理,将要处理的面记入vari,j,k:intege

37、r;beginnum:=0;把握本质,灵活运用动态规划的深入探讨- 94 - IOI99 中国集训队优秀论文选for i:=1 to n dobeginsort(i);ssi,1:=add(aai,1,aai,2);ssi,2:=add(aai,1,aai,3);ssi,3:=add(aai,2,aai,3);end;end;procedure check(ii,nn,hh:integer); 检查用 ii 积木的 nn 放置方式,是否有效varg,h:integer;beginif (pii-10=0) and (pii-10+hh=qiij) then qiij:=pii-10+hh; 考

38、虑另成一堆if (pii-1ssii,nn=0) and (qii-1ssii,nn+hh=qiij) then qiij:=qii-1ssii,nn+hh;考虑放在前一堆上end;beginassign(f1,ToyBrick.in); reset(f1);assign(f2,ToyBrick.out);rewrite(f2); 文件关联、打开 readln(f1,n,m); 读入 N、M 值for i:=1 to n do 读入边长readln(f1,aai,1,aai,2,aai,3);size0,1:=0;size0,2:=0;preprocess; 生成各种待处理的面for i:=0

39、 to n do 动态内存初始化beginnew(pi);new(qi);fillchar(qi,sizeof(qi),0);end;for t:=1 to m do 连续递推 M 阶段,分成 T 堆beginr:=q;q:=p;把握本质,灵活运用动态规划的深入探讨IOI99 中国集训队优秀论文选 - 95 -p:=r; 交换 P、Qfor i:=0 to n do fillchar(qi,sizeof(qi),255); Q 初始化for i:=t to n do 考虑 T 个到 N 个积木beginfor j:=0 to num do 考虑最后“输出”的面的约束条件beginqij:=qi

40、-1j; 当前积木不用if (aai,1=sizej,1) and (aai,2=sizej,2) then check(i,1,aai,3); if (aai,1=sizej,1) and (aai,3=sizej,2) then check(i,2,aai,2);if (aai,2=sizej,1) and (aai,3=sizej,2) then check(i,3,aai,1);如果当前积木的某方向放置可以满足此要求,考虑按此方向放置该块作为新的一堆的底或加在前一堆上(如果可能)end;end;end;writeln(f2,qn0); 输出答案 close(f1);close(f2)e

41、nd.程序 3 IOI98 多边形program Polygon; “多边形”程序varf1,f2:text; 输入、输出文件变量n:integer; 顶点个数data:array 150 of integer; 原始数据- 顶点sign:array 150 of char; 原始数据-运算符i,j,k,l:integer; 辅助变量t,s,p:integer; 辅助变量ans:set of 150; 可能达到最大值的第一次移动的边的序号 best:integer; 当前最优解min,max:array 150,050 of integer;动态规划表格,mini,l表示从第 i 个顶点开始,

42、经过 l 个符号按合理运算所得的结果的最小值;max 与之类似,但为最大值first:boolean; 首次输出标志procedure init; 初始化,读入原始数据vari:integer;ch:char;把握本质,灵活运用动态规划的深入探讨- 96 - IOI99 中国集训队优秀论文选beginreadln(f1,n);for i:=1 to n dobeginrepeatread(f1,ch);until chmaxk,l then maxk,l:=maxk,t+max(k+t+1-1) mod n+1,l-t-1;最大值更新if mink,t+min(k+t+1-1) mod n+1

43、,l-t-1maxk,l then maxk,l:=s;if sbest then begin best:=maxi,n-1; ans:=i endelse if maxi,n-1=best then include(ans,i); 更新全局的最大值writeln(f2,best); 输出最大值 first:=true;for i:=1 to n doif i in ans thenbeginif first then first:=falseelse write(f2, );write(f2,i);end;writeln(f2); 输出首次被移动的边close(f1);close(f2) 关

44、闭文件 end. 结束把握本质,灵活运用动态规划的深入探讨- 98 - IOI99 中国集训队优秀论文选程序 4 ACM97 亚洲区/ 上海赛题 正则表达式匹配program Expression_Match; 正则表达式匹配程序typedatatype=record 预处理数据类型st,ed:char; 起始、结束字符md:01; 重复方式 0:一次;1:0 或多次mt:01; 匹配方式 0:不包含为匹配;1:包含为匹配end;varf1,f2:text; 文件变量s1,s2:string; 正则表达式串、待匹配串str:string;len:integer; 正则表达式预处理后的“长度”d

45、d:array 180 of datatype; 预处理结果pro:array 080,080 of boolean; 动态规划数组fr:array 080,080 of byte; FRi,j表示以第 j 个字符为尾的与前 i 项正则表达式匹配的最前端的字符位置i,j,k,l:integer; 辅助变量ok:boolean; 找到标记ha:boolean;ans:integer;bt,bj:integer; 当前最优值的开始位置、长度procedure preprocess; 预处理,生成规划的“正则表达式”表示vari,j,k:integer;ch,c:char;begini:=0;j:=

46、0;while ifri-1,k) then fri,j:=fri-1,k; 如果起点较早,更新之end;if not (ddi.mt=0) xor (s2k in ddi.stddi.ed) 如果不匹配,则不考虑再退一格的情况then begin ha:=false; break end;把握本质,灵活运用动态规划的深入探讨IOI99 中国集训队优秀论文选 - 101 -end;end;if (i=len) and proi,j and (fri,j0 then writeln(f2,copy(s2,1,bt-1), (, copy(s2,bt,bj), ), copy(s2,bt+bj,l

47、ength(s2)-bt-bj+1) 如果找到,输出else writeln(f2,(),s2) 对于某些理论上讲可以与空串匹配的正则表达式,应看作与第一个字符前的空串匹配,这里作了专门处理else writeln(f2,s2); 否则输出原串end;close(f1);close(f2)end.程序 5 NOI98 免费馅饼说明:动态规划方程: anst,j= max ( anst-1,j+k ) (其中,k=-2,-1,0,1,2,且相应位置可达)program Pizza_For_Free Time Limit:3000;免费馅饼 将允许时间扩大到 3000 秒,分值限制在 longint 范围内typelink=linetype; 指向记录一个时间单位决策数组的指针类型linetype=array 199 of shortint; 记录一个时间单位决策的数组varf1,f2:text; 输入、输出文件变量w,h:integer; 宽度、高度dd:array 0100 of array 199 of longint; 循环使用的数组,用于表示对应时刻、位置的得分值pro:array 03100

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 学术论文 > 毕业论文

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报