动态规划习题精讲
- 格式:doc
- 大小:485.50 KB
- 文档页数:51
动态规划的优化一、时间上的优化花店橱窗布置问题(IOI99试题)。
假设想以最美观的方式布置花店的橱窗,有F束花,每束花的品种都不一样,同时,至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,并从左到右,从1到V顺序编号,V是花瓶的数目,编号为1的花瓶在最左边,编号为V的花瓶在最右边,花束可以移动,并且每束花用1到F的整数唯一标识,标识花束的整数决定了花束在花瓶中列的顺序,即如果I<J,则花束I必须放在花束J左边的花瓶中。
例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有的花束在放入花瓶时必须保持其标识数的顺序,即:杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中。
如果花瓶的数目大于花束的数目,则多余的花瓶必须空,即每个花瓶中只能放一束花。
每一个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数)来表示,空置花瓶的美学值为0。
在上述例子中,花瓶与花束的不同搭配所具有的美学值,可以用如下表格表示:根据表格,杜鹃花放在花瓶2中,会显得非常好看,但若放在花瓶4中则显得很难看。
为取得最佳美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。
题中数据满足下面条件:1≤F≤100,F≤V ≤100,-50≤A IJ≤50,其中A IJ是花束I摆放在花瓶J中的美学值。
输入整数F,V和矩阵(A IJ),输出最大美学值和每束花摆放在各个花瓶中的花瓶编号。
【分析】问题实际就是给定F束花和V个花瓶,以及各束花放到不同花瓶中的美学值,需要你找出一种摆放的方案,使得在满足编号小的花放进编号小的花瓶中的条件下,美学值达到最大。
(1)将问题进行转化,找出问题的原型。
首先,看一下上述题目的样例数据表格。
将摆放方案的要求用表格表现出来,则摆放方案需要满足:每行选且只选一个数(花瓶);摆放方案的相邻两行中,下面一行的花瓶编号要大于上面一行的花瓶编号两个条件。
信息学竞赛中的动态规划专题哈尔滨工业大学周谷越【关键字】动态规划动机状态典型题目辅助方法优化方法【摘要】本文针对信息学竞赛(面向中学生的Noi以及面向大学生的ACM/ICPC)中的动态规划算法,从动机入手,讨论了动态规划的基本思想和常见应用方法。
通过一些常见的经典题目来归纳动态规划的一般作法并从理论上加以分析和说明。
并介绍了一些解决动态规划问题时的一些辅助技巧和优化方法。
纵观全文可知,动态规划的关键在于把握本质思想的基础上灵活运用。
【目录】1.动态规划的动机和基本思想1.1.解决重复子问题1.2.解决复杂贪心问题2.动态规划状态的划分方法2.1.一维状态划分2.2.二维状态划分2.3.树型状态划分3.动态规划的辅助与优化方法3.1.常见辅助方法3.2.常见优化方法4.近年来Noi动态规划题目分析4.1 Noi2005瑰丽华尔兹4.2 Noi2005聪聪与可可4.3 Noi2006网络收费4.4 Noi2006千年虫附录参考书籍与相关材料1.动态规划的动机和基本思想首先声明,这里所说的动态规划的动机是从竞赛角度出发的动机。
1.1 解决重复子问题对于很多问题,我们利用分治的思想,可以把大问题分解成若干小问题,然后再把各个小问题的答案组合起来,得到大问题的解答。
这类问题的共同点是小问题和大问题的本质相同。
很多分治法可以解决的问题(如quick_sort,hanoi_tower等)都是把大问题化成2个以内的不相重复的小问题,解决的问题数量即为∑(log2n / k)。
而考虑下面这个问题:USACO 1.4.3 Number Triangleshttp://122.139.62.222/problem.php?id=1417【题目描述】考虑在下面被显示的数字金字塔。
写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。
每一步可以走到左下方的点也可以到达右下方的点。
73 88 1 02 7 4 44 5 2 6 1在上面的样例中,从7到3到8到7到5的路径产生了最大和:30。
动态规划动态规划是运筹学的一个分支,它是解决多阶段决策过程最优化问题的一种方法。
该方法是由美国数学家贝尔曼(R.Bellman)等人在本世纪50年代初提出的。
他们针对多阶段决策问题的特点,提出了解决这类问题的“最优化原理”,并成功地解决了生产管理、工程技术等方面的许多实际问题,从而建立了运筹学的一个新分支——动态规划。
他的名著《动态规划》于1957年出版,该书是动态规划的第一本著作。
动态规划是现代企业管理中的一种重要决策方法,在工程技术、经济管理、工农业生产及军事及其它部们都有广泛的应用,并且获得了显著的效果。
动态规划可用于解决最优路径问题、资源分配问题、生产计划与库存问题、投资分配问题、装载问题、设备更新与维修问题、排序问题及生产过程的最优控制等。
由于它所具有独特的解题思路,在处理某些优化问题时,常常比线性规划或非线性规划方法更有效。
第一节动态规划的基本方法多阶段决策的实际问题很多,下面通过具体例子,说明什么是动态规划模型及其求解方法。
例1:最短路线问题某工厂需要把一批货物从城市A运到城市E,中间可经过B1 、B2、B3、C1、C2、C3、D1、D2等城市,各城市之间的交通线和距离如下图所示,问应该选择一条什么路线,使得从A到E的距离最短?下面引进几个动态规划的基本概念和相关符号。
(1)阶段(Stage)把所给问题的过程,按时间和空间特征划分成若干个相互联系的阶段,以便按次序去求每个阶段的解,阶段总数一般用字母n表示,用字母k表示阶段变量。
如例l中 (最短路线问题)可看作是n=4阶段的动态规划问题,k=2表示处于第二阶段。
(2)状态(State)状态表示每个阶段开始时系统所处的自然状况或客观条件,它描述了研究问题过程状况。
描述各阶段状态的变量称为状态变量,常用字母sk表示第k阶段的状态变量,状态变量的取值范围称为状态集,用Sk表示。
如例l中,第一阶段的状态为A(即出发位置)。
第二阶段有三个状态:B1 、B2、B3,状态变量s2=B2表示第2阶段系统所处的位置是B2。
动态规划的优化一、时间上的优化花店橱窗布置问题(IOI99试题)。
假设想以最美观的方式布置花店的橱窗,有F束花,每束花的品种都不一样,同时,至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定的,并从左到右,从1到V顺序编号,V是花瓶的数目,编号为1的花瓶在最左边,编号为V的花瓶在最右边,花束可以移动,并且每束花用1到F的整数唯一标识,标识花束的整数决定了花束在花瓶中列的顺序,即如果I<J,则花束I必须放在花束J左边的花瓶中。
例如,假设杜鹃花的标识数为1,秋海棠的标识数为2,康乃馨的标识数为3,所有的花束在放入花瓶时必须保持其标识数的顺序,即:杜鹃花必须放在秋海棠左边的花瓶中,秋海棠必须放在康乃馨左边的花瓶中。
如果花瓶的数目大于花束的数目,则多余的花瓶必须空,即每个花瓶中只能放一束花。
每一个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数)来表示,空置花瓶的美学值为0。
在上述例子中,花瓶与花束的不同搭配所具有的美学值,可以用如下表格表示:根据表格,杜鹃花放在花瓶2中,会显得非常好看,但若放在花瓶4中则显得很难看。
为取得最佳美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。
题中数据满足下面条件:1≤F≤100,F≤V ≤100,-50≤A IJ≤50,其中A IJ是花束I摆放在花瓶J中的美学值。
输入整数F,V和矩阵(A IJ),输出最大美学值和每束花摆放在各个花瓶中的花瓶编号。
【分析】问题实际就是给定F束花和V个花瓶,以及各束花放到不同花瓶中的美学值,需要你找出一种摆放的方案,使得在满足编号小的花放进编号小的花瓶中的条件下,美学值达到最大。
(1)将问题进行转化,找出问题的原型。
首先,看一下上述题目的样例数据表格。
将摆放方案的要求用表格表现出来,则摆放方案需要满足:每行选且只选一个数(花瓶);摆放方案的相邻两行中,下面一行的花瓶编号要大于上面一行的花瓶编号两个条件。
第9章动态规划应用举例习题详解(习题)9. 1有一部货车每天沿着公路给四个零售店卸下6箱货物,如果各零售店出售该货物所得利润如表9-1所示,试求在各零售店卸下几箱货物,能使获得总利润最大?其值是多少?9.2设有某种肥料共6个单位重量,准备供给四块粮田用。
其每块田施肥数量与增产粮食数字关系如表9-2所示。
试求对每块田施多少单位重量的肥料,才使总的增产粮食最多。
粮田增肥1234000001202518282424539473605761654756578745857090806907395859.3某公司打算向它的三个营业区增设六个销售店,每个营业区至少增设一个。
从各区赚取的利润(单位为万元)与增设的销售店个数有关,其数据如表9-3所示。
销售店增加数A区利润B区利润C区利润9.4某工厂有100台机器,拟分四个周期使用,在每一周期有两种生产任务。
据经验,把机器q 台投入第一种生产任务,则在一个生产周期中将有;n/3台机器作废;余下的机器全部投入第二种生产任务,则有1/10台机器作废。
如果干第一种生产任务每台机器可收益10, 干第二种生产任务每台机器可收益7。
问怎样分配机器,使总收益最大?9. 5设有三种资源,每单位的成本分别为a、b. co给定的利润函数为n(xi, yi,z),(/ = 1,2,•••,«)现有资金为W,应购买各种资源多少单位分配给"个行业,才能使总利润最大。
试给出动态规划的公式,并写出它的一维递推关系式。
9. 6某厂生产一种产品,估计该产品在未来4个月的销售量分别为400、500、300、200件。
该项产品的生产准备费用每批为500元,每件的生产费用为1元,存储费用每件每月为1 元。
假定1月初的存货为100件,4月底的存货为零。
试求该厂在这4个月内的最优生产计划。
9.7某电视机厂为生产电视机而需生产喇叭,生产以万只为单位。
根据以往记录,一年的四个季度需要喇叭分别是3万、2万、3万、2万只。
第七章动态规划规划问题的最终目的就是确定各决策变量的取值,以使目标函数达到极大或极小。
在线性规划和非线性规划中,决策变量都是以集合的形式被一次性处理的;然而,有时我们也会面对决策变量需分期、分批处理的多阶段决策问题。
所谓多阶段决策问题是指这样一类活动过程:它可以分解为若干个互相联系的阶段,在每一阶段分别对应着一组可供选取的决策集合;即构成过程的每个阶段都需要进行一次决策的决策问题。
将各个阶段的决策综合起来构成一个决策序列,称为一个策略。
显然,由于各个阶段选取的决策不同,对应整个过程可以有一系列不同的策略。
当过程采取某个具体策略时,相应可以得到一个确定的效果,采取不同的策略,就会得到不同的效果。
多阶段的决策问题,就是要在所有可能采取的策略中选取一个最优的策略,以便得到最佳的效果。
动态规划(dynamic programming)同前面介绍过的各种优化方法不同,它不是一种算法,而是考察问题的一种途径。
动态规划是一种求解多阶段决策问题的系统技术,可以说它横跨整个规划领域(线性规划和非线性规划)。
当然,由于动态规划不是一种特定的算法,因而它不象线性规划那样有一个标准的数学表达式和明确定义的一组规则,动态规划必须对具体问题进行具体的分析处理。
在多阶段决策问题中,有些问题对阶段的划分具有明显的时序性,动态规划的“动态”二字也由此而得名。
动态规划的主要创始人是美国数学家贝尔曼(Bellman)。
20世纪40年代末50年代初,当时在兰德公司(Rand Corporation)从事研究工作的贝尔曼首先提出了动态规划的概念。
1957年贝尔曼发表了数篇研究论文,并出版了他的第一部著作《动态规划》。
该著作成为了当时唯一的进一步研究和应用动态规划的理论源泉。
1961年贝尔曼出版了他的第二部著作,并于1962年同杜瑞佛思(Dreyfus)合作出版了第三部著作。
在贝尔曼及其助手们致力于发展和推广这一技术的同时,其他一些学者也对动态规划的发展做出了重大的贡献,其中最值得一提的是爱尔思(Aris)和梅特顿(Mitten)。
动态规划算法详解及经典例题⼀、基本概念(1)⼀种使⽤多阶段决策过程最优的通⽤⽅法。
(2)动态规划过程是:每次决策依赖于当前状态,⼜随即引起状态的转移。
⼀个决策序列就是在变化的状态中产⽣出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
假设问题是由交叠的⼦问题所构成,我们就能够⽤动态规划技术来解决它。
⼀般来说,这种⼦问题出⾃对给定问题求解的递推关系中,这个递推关系包括了同样问题的更⼩⼦问题的解。
动态规划法建议,与其对交叠⼦问题⼀次重新的求解,不如把每⼀个较⼩⼦问题仅仅求解⼀次并把结果记录在表中(动态规划也是空间换时间的)。
这样就能够从表中得到原始问题的解。
(3)动态规划经常常使⽤于解决最优化问题,这些问题多表现为多阶段决策。
关于多阶段决策:在实际中,⼈们经常遇到这样⼀类决策问题,即因为过程的特殊性,能够将决策的全过程根据时间或空间划分若⼲个联系的阶段。
⽽在各阶段中。
⼈们都须要作出⽅案的选择。
我们称之为决策。
⽽且当⼀个阶段的决策之后,经常影响到下⼀个阶段的决策,从⽽影响整个过程的活动。
这样,各个阶段所确定的决策就构成⼀个决策序列,常称之为策略。
因为各个阶段可供选择的决策往往不⽌⼀个。
因⽽就可能有很多决策以供选择,这些可供选择的策略构成⼀个集合,我们称之为同意策略集合(简称策略集合)。
每⼀个策略都对应地确定⼀种活动的效果。
我们假定这个效果能够⽤数量来衡量。
因为不同的策略经常导致不同的效果,因此,怎样在同意策略集合中选择⼀个策略,使其在预定的标准下达到最好的效果。
经常是⼈们所关⼼的问题。
我们称这种策略为最优策略,这类问题就称为多阶段决策问题。
(4)多阶段决策问题举例:机器负荷分配问题某种机器能够在⾼低两种不同的负荷下进⾏⽣产。
在⾼负荷下⽣产时。
产品的年产量g和投⼊⽣产的机器数量x的关系为g=g(x),这时的年完善率为a,即假设年初完善机器数为x,到年终时完善的机器数为a*x(0<a<1);在低负荷下⽣产时,产品的年产量h和投⼊⽣产的机器数量y的关系为h=h(y)。
第一题导弹拦截本题第一问实际上是给出数列a1..a n,求最长非递增序列的长度,{容易想到以n来划分子问题,即分别求a1..a n-1, a1..a n-2, …, a1,中最长非递增序列长度,但各级子问题之间不易建立转化关系}将子问题具体一些,我们可以用f[k]表示数列a1..a k中以a k结尾的最长非递增序列的长度,题目所求即为max{f[1..n]}。
转移方程为f[n]=max{f[k]}+1;(0<=k<n,a[n]<=a[k] )设a[0]= -maxint,f[0]=0;第二问可以用贪心做,设拦截前k个导弹用o2个系统,其最后拦截的高度分别为l[1]..l[o2],则拦截第k+1个导弹时,找能够拦截这枚导弹的系统中最后拦截高度最小的,若没有这样的系统则新增一个系统。
附源程序:const max = 10000;type arr = array[0..max]of integer;var d,l : arr;i,j,k,m,n,o1,o2,t : longint;procedure input;beginfillchar(d,sizeof(d),0);fillchar(l,sizeof(l),0);writeln('input:');i:=0;repeati:=i+1;read(d[i]);until eoln;t:=i;o1:=0; o2:=0;end;procedure output;beginwriteln('Output:');writeln(o1);writeln(o2);end;procedure main1;beginl[t]:=1;for i:=t-1 downto 1 do begink:=0;for j:=i+1 to t doif (l[j]>k)and(d[i]>=d[j]) then k:=l[j];l[i]:=k+1;end;for i:=1 to t doif l[i]>o1 then o1:=l[i];end;procedure main2;beginfor i:=0 to t do l[i]:=maxint;o2:=1;for i:=1 to t do begink:=0;for j:=1 to o2 doif (l[j]>=d[i])and(l[j]<=l[k]) then k:=j;if k=0 then begino2:=o2+1;k:=o2;end;l[k]:=d[i];end;end;begininput;main1;main2;output;end.第二题 石子合并设f[i,j](i<=j)表示将第i 堆到第j 堆石子合并为一堆所得的最大分数(最小时类似)。
常见动态规划题⽬详解1.爬楼梯题⽬描述:假设你正在爬楼梯。
需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。
你有多少种不同的⽅法可以爬到楼顶呢?注意:给定 n 是⼀个正整数。
⽰例 1:输⼊: 2输出: 2解释:有两种⽅法可以爬到楼顶。
1. 1 阶 + 1 阶2. 2 阶⽰例 2:输⼊: 3输出: 3解释:有三种⽅法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶2. 1 阶 + 2 阶3. 2 阶 + 1 阶实现代码:class Solution {public:int climbStairs(int n) {vector<int> a(n);a[0] = 1;a[1] = 2;if(n == 1){return 1;}if(n == 2){return 2;}for(int i = 2; i < n;i++){a[i] = a[i - 1] + a[i - 2];}return a[n - 1];}};2.变态跳台阶题⽬描述:⼀只青蛙⼀次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上⼀个n级的台阶总共有多少种跳法。
实现代码:class Solution {public:int jumpFloorII(int number) {if(number == 0){return 0;}int total = 1;for(int i = 1; i < number; i++){total *= 2;}return total;}};3.n年后⽜的数量题⽬描述:假设农场中的母⽜每年会产⽣⼀头⼩母⽜,并且永远不会死。
第⼀年农场中只有⼀头成熟的母⽜,第⼆年开始,母⽜开始⽣⼩母⽜,每只⼩母⽜三年之后成熟⼜可以⽣⼩母⽜,给定整数N,求N年后母⽜的数量。
实现代码:class solution{ public: int f(int n){ if(n < 1){ return 0; } if(n == 1|| n== 2||n == 3){ return n; } int res = 3; int pre = 2; int prepre = 1; int tmp1=0; int tmp2 = 0; for(int i = 4;i < n;i++){ tmp1 = res; tmp2 = pre; res = pre + prepre; pre = tmp1; prepre = tmp2; } return res; }};4.矩形覆盖题⽬描述:我们可以⽤2*1的⼩矩形横着或者竖着去覆盖更⼤的矩形。
信息学竞赛中的动态规划专题哈尔滨工业大学周谷越【关键字】动态规划动机状态典型题目辅助方法优化方法【摘要】本文针对信息学竞赛(面向中学生的Noi以及面向大学生的ACM/ICPC)中的动态规划算法,从动机入手,讨论了动态规划的基本思想和常见应用方法。
通过一些常见的经典题目来归纳动态规划的一般作法并从理论上加以分析和说明。
并介绍了一些解决动态规划问题时的一些辅助技巧和优化方法。
纵观全文可知,动态规划的关键在于把握本质思想的基础上灵活运用。
【目录】1.动态规划的动机和基本思想1.1.解决重复子问题1.2.解决复杂贪心问题2.动态规划状态的划分方法2.1.一维状态划分2.2.二维状态划分2.3.树型状态划分3.动态规划的辅助与优化方法3.1.常见辅助方法3.2.常见优化方法4.近年来Noi动态规划题目分析4.1 Noi2005瑰丽华尔兹4.2 Noi2005聪聪与可可4.3 Noi2006网络收费4.4 Noi2006千年虫附录参考书籍与相关材料1.动态规划的动机和基本思想首先声明,这里所说的动态规划的动机是从竞赛角度出发的动机。
1.1 解决重复子问题对于很多问题,我们利用分治的思想,可以把大问题分解成若干小问题,然后再把各个小问题的答案组合起来,得到大问题的解答。
这类问题的共同点是小问题和大问题的本质相同。
很多分治法可以解决的问题(如quick_sort,hanoi_tower等)都是把大问题化成2个以内的不相重复的小问题,解决的问题数量即为∑(log2n / k)。
而考虑下面这个问题:USACO 1.4.3 Number Triangleshttp://122.139.62.222/problem.php?id=1417【题目描述】考虑在下面被显示的数字金字塔。
写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。
每一步可以走到左下方的点也可以到达右下方的点。
73 88 1 02 7 4 44 5 2 6 1在上面的样例中,从7到3到8到7到5的路径产生了最大和:30。
【输入格式】第一个行包含R(1<= R<=1000) ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。
【输出格式】单独的一行包含那个可能得到的最大的和。
【样例输入】573 88 1 02 7 4 44 5 2 6 1【样例输出】30显然,我们同样可以把大问题化成小问题来解决。
如样例中最底层的6就可以从次底层的两个4走来,假设分别知道走到次底层的两个4的最优解,那么取其中较大的加上6就是走到最底层的6时的最优解。
然而次底层的两个4还可以走向最底层的2和1,这样就产生了重复的子问题。
动态规划的第一类动机就是为了要避免这种重复运算。
事实上,子问题的个数是确定的,只要我们能够把已经计算过的子问题记录下来,再下次需要时直接使用,便可以大大提高程序的效率。
下面介绍一下动态规划的相关概念。
首先动态规划是来解决最优化问题的,再进一步说就是解决最优化问题中的多阶段决策问题。
以下是动态的定义内容,在各种基础书籍上都有相关讲解,在此仅列出,不做累述。
状态(State):表示事物的性质,是描述动态规划中的单元的量。
阶段(Stage):阶段是一些性质相近的状态集合。
决策(Decision):每个阶段做出的某种选择性行动,是程序所需要完成的选择。
状态转移方程(Equal):是前一个阶段的状态转移到后一个的状态的演变规律,是关于两个相邻阶段状态变化的方程,是动态规划的核心。
初始状态:由已知能够确定的状态。
目标状态:表示解或能够转化为解的状态。
总体看来,由初始状态经过若干阶段通过若干决策推出目标状态的过程就是动态规划。
下面我们就Number Triangles一题对这些概念对号入座:首先确定状态,用F[I,J]表示从顶层走到第I行第J列的点能取得的最大和。
显然每一层为一个阶段。
而对于走到每一个非顶层点的情况来说,最多都只可能由它上方的点或左上方的点走来。
则有状态转移方程:F[I,J] = Max(F[I-1,J], F[I-1,J-1])+ A[I,J];初始状态为F[1,1] = A[1,1];目标状态为F[N,K],其中K∈[1,N]。
要求输出的解则是Max {F[N,K]} ,其中K ∈[1,N]。
时空复杂度均为O(N2)。
这里给出程序主干部分:F[1,1] = A[1,1]For I = 2 to N DoFor J = 1 to I DoIf F[I-1,J] > F[I-1,J-1] ThenF[I,J] = F[I-1,J] + A[I,J]ElseF[I,J] = F[I-1,J-1] + A[I,J]接下来我们从理论上来讨论使用动态规划的条件。
对于一种状态划分的方法来说,状态只与状态本身的性质有关,而与如何达到该状态等其他条件一概无关的性质叫做无后效性。
由于存在无后效性,决策只能从决策本身的性质来确定,使得某一阶段的状态只与它所在阶段的前一阶段的状态有关。
可以看出,存在无后效性是应用动态规划的前提条件。
而考虑动态规划的正确性时,问题则需要满足最优子结构。
所谓最优子结构,即当前一阶段的状态最优时,通过状态转移方程得到的状态也能达到最优。
理论上看,无后效性和最优子结构是使用动态规划时的两个基本条件,而具体应用动态规划时更多凭借的是经验。
下面再引出一道经典题目做一下分析:ACM/ICPC Shanghai2001 Skiinghttp://122.139.62.222/problem.php?id=1862【题目描述】滑雪是一项很受欢迎的体育运动,为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡。
我们想知道载一个区域中最长的滑坡。
区域由一个二维数组给出。
数组的每个数字代表点的高度。
下面是一个例子:1 2 3 4 516 17 18 19 615 24 25 20 714 23 22 21 813 12 11 10 9我们可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。
在上面的例子中,一条可滑行的滑坡为24-17-16-1。
当然25-24-23-...-3-2-1更长。
事实上,这是最长的一条。
【输入格式】输入的第一行表示区域的行数R和列数C(1 <= R,C <= 500)。
下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
【输出格式】输出最长区域的长度。
【样例输入】5 51 2 3 4 516 17 18 19 615 24 25 20 714 23 22 21 813 12 11 10 9【样例输出】25有了前面的例子,不难看出,每个点可以由四个方向中比它高的点滑到。
设DX = {0,1,0,-1},DY = {1,0,-1,0},F[I,J]表示滑到第I行第J列的点时存在的最长滑坡长度,则有状态转移方程:F[I,J] = Max{F[I+DX[K],J+DY[K]]}+ 1,其中要求满足第I+DX[K]行第J+DY[K]列的点存在且高度比第I行第J列的点的高度高。
我们可以按照深度优先搜索的方式计算F,并利用二维数组Arr记录计算过的F值,下面同样给出程序主干部分:Function F (Int I, Int J){If Arr[I,J] > 0 ThenReturn Arr[I,J]Int P, Ans = 0For P = 1 to 4 DoIf ((I+DX[P],J+DY[P]) In Map) And (H[I+DX[P],J+DY[P]] > H[I,J]) ThenIf (Ans < F[I+DX[P],J+DY[P]])Ans = F[I+DX[P],J+DY[P]]Arr[I,J] = Ans + 1Return Arr[I,J]}同样是动态规划,是什么使得两道题目代码的主干部分相差巨大呢?这里讨论一下动态规划的两种实现形式——递推和记忆化搜索。
首先,可以说所有用递推实现的动态规划均可以利用记忆化搜索实现。
而某些题目之所以可以用递推求解,是因为这类题目同一阶段的状态表示上有很大的相关性,比如数字矩阵中某一行或列,这使得我们可以计算一个阶段的所有状态后再计算下一状态。
而某些题目中利用动态规划划分的同一阶段的状态表示上没有多大相关性,比如Skiing里面的状态,从某点做起点每滑动一步为一个阶段,我们无法用一个准确的可以直接利用的集合将一个阶段中的状态表示出来,只能从已知状态去找和它相关联的状态。
对于Skiing我们已知的是目标状态(即四面都不比该点高的点),通过边界条件(即四面都比该点高的最优值为1),便可以进行记忆化搜索。
利用递推实现动态规划时,单位操作时间小,可以方便地使用一些优化;而利用记忆化搜索实现动态规划时,单位操作时间大,但可以避免计算一些不必要的状态。
总地来说,相比于用状态空间搜索的方法解决这类存在重复子问题的题目,使用动态规划增大了空间的开销,但提高了时间效率。
1.2 解决复杂贪心问题接下来,进入下一话题。
我们考虑一下我们熟知的贪心算法和动态规划的关系,我看过很多写贪心算法和动态规划之间区别的材料,在这里我们不谈这个,而是要讨论动态规划与贪心算法之间的联系。
如果我们把每一步贪心作为一个阶段,那么可以认为每个阶段只有一个状态,再把贪心策略看作状态转移方程,那么这样是否也是一种“动态规划”呢?实际上,它们二者之间的差别就在数据的维护上,有很多贪心问题在采取一次贪心策略之后要对数据进行全盘的维护,而我们讲的动态规划一般没有这个步骤。
而这个维护的目的是什么呢?是为了保证正确性,和动态规划中的最优子结构的目的一样,那么就说明目前的状态划分不具有最优子结构,那么我们是否能够通过改变状态的划分方法来代替这个维护并使新划分的状态具有最优子结构呢?这里直接给出结论:对于某些分步讨论的贪心决策问题,我们可以通过扩展状态使之能够用动态规划解决。
扩展出的状态的作用就是为了保证正确性,也就是保证最优子结构。
举一个简单的例子:给出N个数,要从其中取M个求和,并使和尽量大。
这明显是一个贪心可解的问题,把数字从大到小排序后取前M个求和即可。
那么我们同样也可以扩展出一部分状态。
我们设F[I,J]表示前I个数字中取了J个数字得到的最大和,则有:F[I,J] = Max (F[I–1,J],F[I-1][J-1] + A[J])。
那些贪心算法并不用考虑的“多余”状态就是扩展出的状态,举个实例来说明:N = 5 , M = 3时,A[] = {1, 2, 3, 4, 5}。
那么显然1和2都不会被取到,但数组F中的F[1,1], F[2,1] 和F[2,2]都是由1和2组成的状态,从贪心的角度看,它们就是多余的,就是为了使用动态规划扩展出来的状态。