收藏 分享(赏)

动态规划教程——pascal语言描述.doc

上传人:weiwoduzun 文档编号:4032186 上传时间:2018-12-05 格式:DOC 页数:46 大小:504.01KB
下载 相关 举报
动态规划教程——pascal语言描述.doc_第1页
第1页 / 共46页
动态规划教程——pascal语言描述.doc_第2页
第2页 / 共46页
动态规划教程——pascal语言描述.doc_第3页
第3页 / 共46页
动态规划教程——pascal语言描述.doc_第4页
第4页 / 共46页
动态规划教程——pascal语言描述.doc_第5页
第5页 / 共46页
点击查看更多>>
资源描述

1、动态规划教程pascal 语言描述第一节 动态规划基本概念一,动态规划三要素:阶段,状态,决策。他们的概念到处都是,我就不多 说了,我只 说说我对他们的理解:如果把动态规划的求解过程看成一个工厂的生产线,阶段就是生 产某个商品的不同的环节,状 态就是工件当前的形态,决策就是对 工件的操作。 显然不同阶段是 对产品的一个前面各个状态的小结,有一个个的小结构成了最终的整个生产线。每个状 态间又有关联(下一个状 态是由上一个状态做了某个决策后产生的)。下面举个例子:要生产一批雪糕,在这个过程中要分好多 环节:购买牛奶,对牛奶提纯处理,放入工厂加工,加工后的商品要包装,包装后就去销售 ,这样没个环节就

2、可以看做是一个 阶段;产品在不同的时候有不同的状态,刚开始时只是白白的牛奶,进 入生产后做成了各种造型,从冷冻库拿出来后就变成雪糕(由液态变成固态=_=|)。每个形 态就是一个状 态,那从液 态变成固态经过了冰 冻这一操作,这个操作就是一个决策。一个状态经过一个决策变成了另外一个状态,这个过程就是状 态转移,用来描述状 态转移的方程就是状态转移方程。经过这个例子相信大家对动态规划有所了解了吧。下面在说说我对动态规划的另外一个理解:用图论知识理解动态规划:把动态规划中的状态抽象成一个点,在有直接关联的状态间连一条有向边,状态转移的代价就是边上的权。 这样就形成了一个有向无 环图 AOE 网(为什

3、么无环呢?往下看)。对这个图进行拓扑排序,删除一个边后同 时出现入度为 0 的状态在同一 阶段。 这样对图求最优路径就是动态规划问题的求解。二,动态规划的适用范围动态规划用于解决多阶段决策最优化问题,但是不是所有的最优化问题都可以用动态规划解答呢?一般在题目中出现求最优解的问题就要考虑动态规划了,但是否可以用还要满足两个条件:最优子结构(最优化原理)无后效性最优化原理在下面的最短路径问题中有详细的解答;什么是无后效性呢?就是说在状态 i 求解时用到状 态 j 而状态 j 就解有用到状态 k状态 N。而求状态 N 时有用到了状态 i 这样求解状态的过程形成了环就没法用动态规划解答了,这也是上面用

4、图论理解动态规划中形成的图无环的原因。也就是说当前状态是前面状态的完美总结,现在与过去无关。 。当然,有是换一个划分状态或 阶段的方法就满足无后效性了,这样的问题仍然可以用动态规划解。三,动态规划解决问题的一般思路。拿到多阶段决策最优化问题后,第一步要判断 这个问题是否可以用 动态规划解决,如果不能就要考 虑搜索或贪心了。当却定问题可以用 动态规划后,就要用下面介绍的方法解决问题了:(1)模型匹配法:最先考虑的就是这个方法了。挖掘 问题的本质,如果 发现问题 是自己熟悉的某个基本的模型,就直接套用,但要小心其中的一些小的变动, 现在考题办都是基本模型的 变形套用时要小心条件,三思而后行。 这些

5、基本模型在先面的分类中将一一介绍。(2)三要素法仔细分析问题尝试着确定动态规划的三要素,不同 问题的却定方向不同:先确定阶段的问题:数塔问题,和走路 问题(详见解题报告)先确定状态的问题:大多数都是先确定状态的。先确定决策的问题:背包问题。 (详见解题报告)一般都是先从比较明显的地方入手,至于怎么知道哪个明 显就是经验问题了,多做 题就会发现。(3)寻找规律法:这个方法很简单,耐心推几组 数据后,看他 们的规律,总结规律间的共性,有点贪心的意思。(4)边界条件法找到问题的边界条件,然后考 虑边界条件与它的领接状态 之间的关系。 这个方法也很起效。(5)放宽约束和增加约束这个思想是在陈启锋的论文

6、里看到的,具体内容就是 给问题 增加一些条件或删除一些条件使问题变的清晰。第二节 动态规划分类讨论这里用状态维数对动态规划进行了分类:1.状态是一维的11 下降/非降子序列问题:问题描述: 挖掘题目的本质 ,一但抽象成这样的描述就可以用这个方法解在一个无序的序列 a1,a2,a3,a4an 里,找到一个最长的序列满足:aiajakam,且 ijkm.(最长下降子序列)。问题分析:如果前 i-1 个数中用到 ak (akai 或 akai(或ajai) 最长下降子序列实现求解的部分代码:opt0:=maxsize;maxsize 为 maxlongint 或-maxlongintfor i:=1

7、 to n dofor j:=0 to i-1 doif ( ajai) and (optj+1opti) then opti:=optj+1;ans:=-maxlongint;for i:=1 to n doif optians then ans:=opti; ans 为最终解复杂度:从上面的实现不难看出时间复杂度为 O(N2),空间复杂度 O(N);例题 1 拦截导弹 (missile.pas/c/cpp) 来源:NOIP1999(提高组) 第一题【问题描述】某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统 。但是 这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以

8、后每一发炮弹 都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还 在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。输入导弹依次飞来的高度(雷达给出的高度数据是不大于 30000 的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹 最少要配备多少套这种导弹拦 截系统。【输入文件】missile.in单独一行列出导弹依次飞来的高度。【输出文件】missile.out两行,分别是最多能拦截的导弹 数,要 拦截所有导弹最少要配 备的系统数【输入样例】389 207 155 300 299 170 158 65【输出样例】62【问题分析】有经验的选手不难看出这是

9、一个求最长非升子序列问题,显然标准算法是动态规划。以导弹依次飞来的顺序为阶段, 设计状态 opti表示前 i 个 导弹中拦截了导弹 i 可以拦截最多能拦截到的导弹的个数。状态转移方程:opti=max(optj)+1 (hi=hj,0=ai) and (optj+1opti) thenopti:=optj+1;anslen:=0;for i:=1 to n doif optianslen thenanslen:=opti;fillchar(opt,sizeof(opt),0);a0:=-maxlongint;for i:=1 to n dofor j:=i-1 downto 0 doif (a

10、jopti) thenopti:=optj+1;anstime:=0;for i:=1 to n doif optianstime thenanstime:=opti;end;procedure print;beginwriteln(anslen);writeln(anstime);close(input);close(output);end;begininit;main;print;end.例题二 合唱队形 (chorus.pas/c/cpp) 来源:NOIP2004(提高组) 第一题N 位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的 K 位同学排成合唱队形。合唱队形是指

11、这样的一种队形:设 K 位同学从左到右依次编号为 1,2,K,他们的身高分别为T1,T2,TK, 则他们的身高 满足 T1Ti+1TK(1opt1i) thenopt1i:=opt1j+1;an+1:=-maxlongint;for i:=n downto 1 dofor j:=i+1 to n+1 doif (ajopt2i) thenopt2i:=opt2j+1;ans:=0;for i:=1 to n doif opt1i+opt2ians thenans:=opt1i+opt2i;end;procedure print;beginwriteln(n-ans+1);close(input

12、);close(output);end;begininit;main;print;end.例题 3 Buy Low Buy Lower (buylow.pas/c/cpp) 来源: USACO 4-3-1【问题描述】“逢低吸纳”是炒股的一条成功秘诀。如果你想成为一个成功的投资者,就要遵守这条秘诀:“逢低吸纳,越低越 买“这句话的意思是:每次你购买股票时的股价一定要比你上次购买时的股价低.按照这个规则购买股票的次数越多越好,看看你最多能按这个规则买几次。给定连续的 N 天中每天的股价。你可以在任何一天购买一次股票,但是购买时的股价一定要比你上次购买时的股价低。写一个程序,求出最多能买几次股票。以

13、下面这个表为例, 某几天的股价是:天数 1 2 3 4 5 6 7 8 9 10 11 12股价 68 69 54 64 68 64 70 67 78 62 98 87这个例子中, 聪明的投资者(按上面的定义),如果每次买股票时的股价都比上一次买时低,那么他最多能买 4 次股票。一种买法如下 (可能有其他的买法):天数 2 5 6 10股价 69 68 64 62【输入文件】buylow.in第 1 行: N (1 =aj,0=ai,optj=opti-1) sum 代表求和 答案=sum(F(j) 0ai) and (optj+1opti) thenopti:=optj+1;for i:=1

14、 to n dobeginj:=i-1;while (j0) and (optiaj) dodec(j);nexti:=j;end;F0,1:=1;for i:=1 to n+1 dofor j:=i-1 downto nexti doif (optj=opti-1) and (ajai) thenHinc(Fi,Fj);end;procedure print;vari,top,m:longint;beginwrite(optn+1-1, );top:=maxsize;while (top1) and (Fn+1top=0) dodec(top);write(Fn+1,top);for i:=

15、top-1 downto 1 dobeginm:=Fn+1,i;while mD2 那么一定会相交,反之则不会相交。当 C1 C2 时,如果 D1x dodec(j);if ij;if jL then quick(L,j);if iopti) thenopti:=optj+1;ans:=-maxlongint;for i:=1 to n doif ans0) dobegininit;main;read(x,y);end;close(input);close(output);end.1.2 背包问题首先说说背包问题的基本模型:现有 N 个物品,每个物品的价值为 V,重量为 W。求用一个载重量为

16、S 的背包装这写物品,使得所装物品的总价值最高。背包问题用贪心和搜索解,当然效果不佳,不过在我的贪心和搜索总结中会说到。显然标准的解法是动态规化,我在解决这个问题时习惯设计 一维状态, 还可以 设计二维的,二维状态在下面会讲,现在只讨论用一维状态实现背包问题。背包问题的分类:(1)小数背包:物品的重量是实数,如油,水等可以取 1.67 升 (2)整数背包:0/1 背包:每个物品只能 选一次,或不 选。不能只选一部分部分背包:所选物品可以是一部分。(3)多重背包:背包不只一个。小数背包:在贪心总结中会细讲。整数背包:部分背包:同小数背包。0/1 背包:这个问题是最经常出 现的问题, 应该熟练掌握

17、。我们先看一下 0/1 背包的简化版:现有 N 个物品,每个物品重量为 W,这些物品能否使在载重量为 S 的背包装满(即重量和正好为 S)?如过不能那能使物品重量和最重达到多少?针对这一问题我们以物品的个数分阶段, 设计一个状态 opti表示载重量为 i 的背包可否装满, 显然opti的基类型是 boolean。决策是什么呢?当要装第 i 个物品时,如果前 i-1 个物品可以使载重为 k 的背包装满,那么载重为 k+wi的背包就可以装满。于是对于一个 optj来 说,只要 optj-wi是 true(表示可装 满)那 optj就可以装满,但要注意:针对每一个物品枚举背包的载重量时如果这样正向的

18、推导会使同一个物品用好几次,因 为 k+wi可装满那k+wi+wi就可装满,但实际 上是装不满的因为物品只有一个。解决这个问题很简单,只要逆向推导就 OK了。这样划分阶段,设计状态,满足无后效性和么?显然对与一个每一个阶段都是独立的,物品的 顺序并不影响求解,因为装物品的次序不限。而对于optj只考虑 optj-wi而不考 虑后面的,所以 满足无后效性。有了上面的分析不难写出状态转移方程:optj:=optj-w1 optj-wi=true时间复杂度:阶段数 O(S)*状态数(O(N))*转移代价(O(1))=O(SN)下面看几个例题:例题 5 装箱问题 (pack.pas/c/cpp) 来源

19、:NOIP2001(普及组) 第四题【问题描述】有一个箱子容量为 V(正整数,0V20000),同时有 n 个物品(0n30,每个物品有一个体积(正整数)。要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。【输入文件】第一 行一个正整数 V 表示箱子的容量,第二行一个正整数 N 表示物品个数,接下来 N 行列出这 N 个物品各自的体积。【输出文件】单独一行,表示箱子最小的剩余空间。【输入样例】2468312797【输出样例】0【问题分析】本题是经典的 0/1 背包问题,并且是 0/1 背包的简化版,把箱子看做背包,容量看做载重量,体积看做重量,剩余空间最小也就是尽量装 满背包。于

20、是 这个问题便成了:有一个栽重量为 V 的背包,有 N 个物品,尽量多装物品,使背包尽量的重。设计一个状态 opti表示重量 i 可否构成。状态转移方程:optj:=optj-w1 optj-wi=true最终的解就是 v-x(x0 dobegininc(top);atop:=m;inc(tothig,m);read(m);end;for i:=1 to top dofor j:=tothig downto 1 doif (j-ai=0) and (optii,j-ai) thenoptii,j:=true;end;ans:=maxhig;while not opt1,ans dodec(an

21、s);while not can(ans) dodec(ans);writeln(ans);end;begininit;main;end.回顾上面的内容充分说明动态规划的本质就是递推。其 实 按照我的理解(动规涉及最优决策, 递推是单纯的总结)背包问题的简化版更准确点算是递推而非动态规划,至于动归和递推之间的界线本来就很模糊(至少我这么认为)把它看做什么都可以,没必要咬文嚼字。回到 0/1 背包的原问题上(如果你忘了就去上面看看)。如果在不知道这个模型的情况下我们怎么做这个题呢?这就要用到第一节提到的方法二:三要素法。题目中明确说明对于一个物品要不就拿走要不就放下,其 实题目赤裸裸的告诉我们决

22、策就是不拿(用0 表示)或拿(用 1 表示)。这样 想都不用想就知道了决策,这也是本题的突破口。知道了决策写个搜索的程序应该是很轻松的了。那么阶段是什么呢?显然,给你一堆东西让你往包里塞,你当然是一个一个的那来,塞进去。那么阶段很明显就是物品的个数。状态又是什么呢?有的人在装东西是有个习惯(比如说我)就是先把东西分类,然后把同类的东西打个小包,最后在把小包放进去,我们可以按这个思想 给物品打一些小包,也就是按照单位为 1 的递增的顺序准备好多小包,比如载重是 6 的包,可以为它准 备载重是 1,2,3,4,5 的小包。这样状态就可以想出来了:设计状态 opti,j表示装第 i 个物品时载重为

23、j 的包可以装到的最大价值。opti-1,j (j-wi0)状态转移方程:opti,j=maxopti-1,j,opti-1,j-wi+vi (j-wi=0,i0)(wi:第 i 个物品的重量,vi第 i 个物品的价值)解释:要载重为 j 的背包空出 wi(j-wi)的空间且装上第 i 个物品,比不装获得的价值大就装上它。边界条件:opt0,i=0; (i1S)注:这种二维的状态表示应该在下节讲,但是 为了方便理解先在 这里说了。上面的方法动态规划三要素都很明显,实现也很简单。但是在我初学背包时却用另外一种一维的状态表示法。用第一节说的思考方法五(放宽约束和增加约束)在重新思考一下这个问题:怎

24、么放宽约束呢?把题目中的价值去掉,不考虑 价值即最优就变成背包问题 的简化版了。那 简化版的求解对我们有何启示呢?再一次增加约束:背包只能装满。显然对于 N 个装满背包的方案中只要找到一个价 值最大的就是问题的解。那么装不满怎么办呢?其实装不满背包,它总要达到一定的重量( X)。我 们可以把这种情况看作是装满一个载重为 X 的小包。总结一下上面的思维过程:放宽约束让我们找到问题的突破口和背包问题简化版一样,我们可以却定载重为 S 的背包是否可以装满。增加约束让我们找到问题的求解方法在装满背包的方案中选择最优的一个方案。这样问题就解决了。设计一个状态 optj表示装满载重为 j 的背包可获得的最

25、大价值。对于第 i 个物品,只要 optj-wi可以装满且 optj-wi+vi比 optj大就装上这个物品(更新 optj)。怎么使 optj既有是否构成又有最优的概念呢?optj只表示最优,只不过使初始条件+1 ,判断 optj是否为 0,如果 optj=0 说明 j 装不满。边界条件:opt0=1;状态转移方程:optj=maxoptj-wi (0y then max:=xelse max:=y;end;procedure main;vari,j:longint;beginfillchar(opt,sizeof(opt),0);for i:=1 to n dofor j:=1 to t

26、doif j-wi0) and (optj-wi+vioptj) thenoptj:=optj-wi+vi;ans:=-maxlongint;for i:=1 to t doif optians then ans:=opti;end;procedure print;beginwriteln(ans-1);close(output);end;begininit;main;print;end.例题 9 开心的金明 来源:NOIP2006(普及组)第二题【问题描述】金明今天很开心,家里购置的新房就要 领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪

27、些物品,怎么布置,你说了算,只要不超过 N 元钱就行”。今天一早金明就开始做预算,但是他想 买的东西太多了,肯定会超过妈妈限定的 N 元。于是,他把每件物品规定了一个重要度,分为 5 等:用整数 15 表示,第 5 等最重要。他 还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘 积的总和最大。设第 j 件物品的价格为 vj,重要度 为 wj,共选中了 k 件物品, 编号依次为 j1.jk,则所求的总和为:vj1*wj1+vjk*wjk 请你帮助金明设计一个满足要求的购物单.【输入文件】输入的第 1 行,为两个正整数

28、,用一个空格隔开: N m(其中 N(=0) and (optj-vi0) and (optj-vi+vi*pioptj)thenoptj:=optj-vi+vi*pi;end;end;end;procedure print;vari,ans:longint;beginans:=0;for i:=1 to n doif optians thenans:=opti;writeln(ans-1);end;begininit;main;print;end.例题 10 金明的预算方案 (budget.pas/c/cpp) 来源:NOIP2006 第二题【问题描述】金明今天很开心,家里购置的新房就要 领

29、钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说 :“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 N 元钱就行”。今天一早,金明就开始做预 算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:主件 附件电脑 打印机,扫描仪书柜 图书书桌 台灯,文具工作椅 无如果要买归类为附件的物品,必 须先买该附件所属的主件。每个主件可以有 0 个、1 个或 2 个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的 N 元。于是,他把每件物品规定了一个重要度,分为 5 等:用整数 15 表示,第 5

30、 等最重要。他还从因特网上查到了每件物品的价格(都是10 元的整数倍)。他希望在不超 过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。设第 j 件物品的价格为 vj,重要度为 wj,共 选中了 k 件物品,编号依次为 j1,j2,jk,则所求的总和为:vj1*wj1+vj2*wj2+ +vjk*wjk。(其中*为乘号)请你帮助金明设计一个满足要求的购物单。【输入文件】输入文件 budget.in 的第 1 行,为两个正整数,用一个空格隔开:N m (其中 N(0,表示该物品为附件,q 是所属主件的编号)【输出文件】输出文件 budget.out 只有一个正整数

31、,为不超过总钱数的物品的价格与重要度乘 积的总和的最大值(0 说明花 i 元可以买到物品。这样就不难设计出这个状态的转移方程来:opti=maxopti,opti-wj (i-wj0) and (opti-wj0) (0y then exit(x);exit(y);end;procedure main;vari,j:longint;beginfillchar(opt,sizeof(opt),0);opt0:=1;for j:=1 to m dofor i:=n downto vj doif qj=0 thenbeginif (i-vj=0) and (opti-vj0) thenopti:=m

32、ax(opti,opti-vj+vj*pj);if (i-vj-vq1j=0) and (opti-vj-vq1j0) thenopti:=max(opti,opti-vj-vq1j+vj*pj+vq1j*pq1j);if (i-vj-vq2j=0) and (opti-vj-vq2j0) thenopti:=max(opti,opti-vj-vq2j+vj*pj+vq2j*pq2j);if (i-vj-vq1j-vq2j=0) and (opti-vj-vq1j-vq2j0) thenopti:=max(opti,opti-vj-vq1j-vq2j+vj*pj+vq1j*pq1j+vq2j*

33、pq2j);ans:=max(ans,opti);end;end;procedure print;beginwriteln(ans-1)*10);close(output);end;begininit;main;print;end.上面提到的几个例题都是最基础的题目,而且把 问题抽象后就与背包 问题的基本模型一样了,但有些题目用到了基本模型,要求的解却不一定很模型一样,下面看个例子:例题 11 Money Systems (money.pas/c/cpp) 来源:USACO 2.3【问题描述】母牛们不但创建了他们自己的政府而且选择了建立了自己的货币系统。In their own rebelli

34、ous way,,他们对货币的数值感到好奇。传统地,一个货币系统是由 1,5,10,20 或 25,50, 和 100 的 单位面值组成的。母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值。举例来说, 使用一个货币系统 1,2,5,10,.产生 18 单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它。写一个程序来计算有多少种方法用给 定的货币系统来构造一定数量的面值。保证总数将会适合 long long (C/C+) 和 Int64 (Free Pascal)。【输入文件】货币系统中货币的种类数目是 V (10 thenbegin

35、if optj=0 thenpathj:=i; 只有当前状态没求过才记录方案inc(optj,optj-wi);end;if opttotal=0 thenbeginwriteln(0);halt;end;if opttotal1 thenbeginwriteln(-1);halt;end;i:=total;while i0 dobeginanspathi:=false;i:=i-wpathi;end;end;procedure print;vari:longint;beginfor i:=1 to n doif ansi then write(i, );end;begininit;main;

36、print;end.1.3 其它问题一维动态规划最常见的就是前面总结的最长下降/非降子序列和 0/1 背包问题了,当然还有别的一写题。由于不是很常见所以没有固定的解题模式,到 时候具体问题 具体分析。下面在看一些例子:例题 13 挖地雷问题 (P3.pas/c/cpp) 来源:NOIP1996(提高组)第三题(有改动)【问题描述】在一个地图上有 N 个地窖(N 3 - 4 - 5max=27【Hint】题目中的路径是有向的且无环路(这是我做的改动原题中没有要求)。【问题分析】看到题目的第一影响是贪心以一点出发找与他连接的地窖中地雷数最多的一个。但很容易想到反例:51 2 1 1 1001 1

37、0 00 1 00 10按照贪心答案是 3,但实际上答案是 101。于是就不得不放弃贪心的想法。但是贪心给了我们启示:从一个顶点出发要选择向一个与他相连且以该点出发可以挖到较多雷的点走。(有点拗口)另一种解释:如果一个顶点连同 N 个分量,显然要则一个较大的就是问题的解答,这个定义是满足最优化原理的。那它满足无后效性么?因为图是有向的,所以以与该顶 点相连的点在往下走的路 线中不包括该点。也就是 说图是一个 AOV网(有向无环图)。既然满足最优化原理,且无后效性,我们就可以用动态规划解了。这个问题的阶段就是拓扑序列,但由于 输入是倒三角形,所以我们没必要求拓扑序列,只要从 N 到着求解就可以了

38、。设计状态 opti表示以 i 点出发可以挖到最多的雷的个数。状态转移方程:opti=maxoptj+wi (gi,j=1)(g 存图,wi存第 i 个地窖中的雷的个数)。时间复杂度:状态数 O(n)*转 移代价 O(n)=O(n2)这个题目还要求出路径,可以用一个 辅助数组 path 来记录,pathi表示从第 i 个出发走到的下一个点的编号。求解完只要按 path 记录 的路径输出即可。【源代码】program P3;constfin=P3.in;fout=P3.out;maxn=200;varg:array0maxn,0maxn of longint;n,ans:longint;w,op

39、t,path:array0maxn of longint;procedure init;vari,j:longint;beginassign(input,fin);reset(input);assign(output,fout);rewrite(output);read(n);fillchar(g,sizeof(g),0);for i:=1 to n doread(wi);for i:=1 to n dofor j:=i+1 to n doread(gi,j);close(input);end;procedure main;vari,j:longint;beginfillchar(opt,si

40、zeof(opt),0);fillchar(path,sizeof(path),0);for i:=n downto 1 dobeginfor j:=i+1 to n doif (gi,j=1) and (optjopti) thenbeginopti:=optj;pathi:=j;end;inc(opti,wi);end;ans:=1;for i:=2 to n doif optioptans then ans:=i;end;procedure print;vari:longint;beginwrite(ans);i:=pathans;while i0 dobeginwrite(,i);i:

41、=pathi;end;writeln;writeln(max=,optans);close(output);end;begininit;main;print;end.2.状态是二维的通过前面的学习,我想因该对动态规 划不陌生了,我学 习动态规 划是没这么系统,二维,一维一起上。二维状态的动态规划是重中之重。所谓二维状态就是说一般设计的状态是 opti,j形式的。那 i,j 可以代表什么呢?有很多朋友问过我这个问题,我的回答是:(1)i,j 组合起来代表一个点的坐标(显然是平面坐标系)(如:街道问题)。(2)i,j 组合表示一个矩阵的单元的位置(第 i 行,第 j 列)(如:数塔问题)(3)起点

42、为 i 长度为 j 的区间。 (如:回文词)(4)起点为 i 终点为 j 的区间。 (如:石子合并问题)(5)两个没关联的事物,事物 1 的第 i 个位置, 对应事物 2 的第 j 个位置(花店橱窗设计)(6)两个序列,第一个序列的前 i 个位置或第 i 个位置对应第 2 个序列的第 j 个位置或前 j 个位置。 (最长公共子序列)。(7)其它下面通过例题和基本模型进一步说明:2.1 数塔问题数塔问题来源于一道经典的 IOI 的题目,直接 说题通过题目总结公性。以后遇到类似的题目可以参照这个模型。例题 14 数塔问题 (numtri.pas/c/cpp) 来源:IOI94【问题描述】考虑在下面

43、被显示的数字金字塔。写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。每一步可以走到左下方的点也可以到达右下方的点。73 88 1 02 7 4 44 5 2 6 5在上面的样例中,从 7 到 3 到 8 到 7 到 5 的路径产生了最大和:30【输入文件】第一个行包含 R(1=0 所以方程也可以这样写:opti,j=maxopti-1,j,opti-1,j-1+ai,j同理 j=i 时方程也可以写成上面那样,所以方程综合为:opti,j=maxopti-1,j,opti-1,j-1+ai,j(0opti+1,j+1 thenopti,j:=opti+1,j+ai,jels

44、e opti,j:=opti+1,j+1+ai,j;end;procedure print;beginwriteln(opt1,1);close(output);end;begininit;main;print;end.例题 15 Henry 捡钱 (money.pas/c/cpp) 来源:Dream Team 邀请赛【问题描述】最近,Henry 由于失恋 (被某大牛甩掉!)心情很是郁闷.所以,他去了大牛家,寻求 Michael 大牛的帮助,让他尽快从失恋的痛苦中解脱出来.Michael 大牛知道 Henry 是很爱钱的,所以他是费尽脑水,绞尽脑汁想出了一个有趣的游戏,帮助 Henry.Mic

45、hael 感觉自己简直是个天才 (我们从不这么认为),就把这个游戏取名为:Henry 拣钱.为了帮助更多的人采用这种方法早日脱离失恋之苦,Michael 特地选在这次 DT 比赛中把游戏介绍给大家.(大家鼓掌!)其实,这个游戏相当垃圾,目的就是为了满足 Henry 这种具有强烈好钱的心理的人.游戏是这样的:Michael 首先找到了一块方形的土地 ,面积为 m*n(米2). 然后他将土地划分为一平方米大小的方形小格.Michael 在每个格子下都埋有 钱( 用非负数 s 表示,表示人民 币的价值为 s)和炸弹(用负数 s 表示,表示 Henry挖出该方格下的东西会花掉 s 的钱去看病,医炸 弹

46、炸伤的 伤口).游戏的要求就是让 Henry 从一侧的中间列出发,按照下图的 5 种方式前进(前进最大宽度为 5),不能越出方格.他每到一个格子,必定要取走其下相应的东西.直到到达土地的另一侧,游戏结束.不用说也知道,Henry 肯定想得到最多的人民币.所以他偷窥了,Michael 埋钱的全过程,绘成了一 张距阵图.由于他自己手动 找会很麻烦,于是他就找到了学习编程的你.请给帮他找出,最大人民币价值.拣钱路线规则(只有 5 个方向,如下图):H 为 Henry 的出发点,每组数据的出 发点都是最后一行的中 间位置!(前方 5 个格子为当前可以到达的 )【输入文件】第一行为 m n.(n 为奇数

47、),入口点在最后一行的中间接下来为 m*n 的数字距阵.共有 m 行,每行 n 个数字.数字 间用空格隔开.代表该格子下是钱或炸弹.为了方便 Henry 清算,数字全是整数 .【输出文件】一个数,为你所找出的最大人民币价值.【输入样例】6 716 4 3 12 6 0 34 -5 6 7 0 0 26 0 -1 -2 3 6 85 3 4 0 0 -2 7-1 7 4 0 7 -5 60 -1 3 4 12 4 2【输出样例】51【数据范围】N and M0) and (kmax) thenmax:=opti-1,k;opti,j:=max+ai,j;end;ans:=-maxlongint;i:=(1+m) div 2;for j:=i-2 to i+2 doif (j0) and (jans) thenans:=optn,j;end;procedure print;beginwriteln(ans);close(input);close(output

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

当前位置:首页 > 实用文档 > 简明教程

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


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

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

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