动态规划入门教程

来源:互联网 发布:淘宝五星好评忘记截图 编辑:程序博客网 时间:2024/05/03 10:56

多阶段决策过程最优化问题

——动态规划的基本模型

在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线。这种把一个问题看做是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策最优化问题。
【例题1】最短路径问题。图中给出了一个地图,地图中每个顶点代表一个城市,两个城市间的连线代表道路,连线上的数值代表道路的长度。现在,想从城市A到达城市E,怎样走路程最短,最短路程的长度是多少?

【分析】把从A到E的全过程分成四个阶段,用k表示阶段变量,第1阶段有一个初始状态A,两条可供选择的支路ABl、AB2;第2阶段有两个初始状态B1、B2,B1有三条可供选择的支路,B2有两条可供选择的支路……。用dk(xk,xk+1)表示在第k阶段由初始状态xk到下阶段的初始状态xk+1的路径距离,Fk(xk)表示从第k阶段的xk到终点E的最短距离,利用倒推方法求解A到E的最短距离。具体计算过程如下:

    S1:K=4,有:F4(D1)=3,F4(D2)=4,F4(D3)=3    S2: K=3,有:F3(C1)=min{d3(C1,D1)+F4(D1),d3(C1,D2)+F4(d2)}=min{8,10}=8                 F3(C2)=d3(C2,D1)+f4(D1)=5+3=8                 F3(C3)=d3(C3,D3)+f4(D3)=8+3=11                 F3(C4)=d3(C4,D3)+f4(D3)=3+3=6    S2: K=2,有:F2(B1)=min{d2(B1,C1)+F3(C1),d2(B1,C2)+f3(C2),d2(B1,C3)+F3(C3)}=min{9,12,14}=9                 F2(B2)=min{d2(B2,c2)+f3(C2),d2(B2,C4)+F3(C4)}=min{16,10}=10    S4:k=1,有:F1(A)=min{d1(A,B1)+F2(B1),d1(A,B2)+F2(B2)}=min{13,13}=13
因此由A点到E点的全过程的最短路径为A—>B2一>C4—>D3—>E。最短路程长度为13。
从以上过程可以看出,每个阶段中,都求出本阶段的各个初始状态到过程终点E的最短路径和最短距离,当逆序倒推到过程起点A时,便得到了全过程的最短路径及最短距离,同时附带得到了一组最优结果(即各阶段的各状态到终点E的最优结果)。

在上例的多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,称这种解决多阶段决策最优化问题的方法为动态规划方法。

根据上例分析和动态规划的基本概念,可以得到动态规划的基本模型如下:
(1)确定问题的决策对象。
(2)对决策过程划分阶段。
(3)对各阶段确定状态变量。
(4)根据状态变量确定费用函数和目标函数。
(5)建立各阶段状态变量的转移过程,确定状态转移方程。


动态规划的基本知识

动态规划是研究一类最优化问题的方法,在经济、工程技术、企业管理、工农业生产及军事等领域中都有广泛的应用。近年来,在ACM/ICPC中,使用动态规划(或部分应用动态规划思维)求解的题不仅常见,而且形式也多种多样。而在与此相近的各类信息学竞赛中,应用动态规划解题已经成为一种趋势,这和动态规划的优势不无关系。
1、动态规划的常用名词
在学习动态规划之前,先得对下面的名词有所了解。本书将标准名词作了一些简化,便于大家更好的理解。
(1)状态(smte)
对于一个问题,所有可能到达的情况(包括初始情况和目标情况)都称为这个问题的一个状态。
(2)状态变量(sk)
对每个状态k关联一个状态变量sk,它的值表示状态k所对应的问题的当前解值。
(3)决策(decision)
决策是一种选择,对于每一个状态而言,你都可以选择某一种路线或方法,从而到达下一个状态。
(4)决策变量(dk)
在状态k下的决策变量dk的值表示对状态k当前所做出的决策。
(5)策略
策略是一个决策的集合,在我们解决问题的时候,我们将一系列决策记录下来,就是一个策略,其中满足某些最优条件的策略称之为最优策略。
(6)状态转移函数(t)
从一个状态到另一个状态,可以依据一定的规则来前进。我们用一个函数t来描述这样的规则,它将状态i和决策变量di映射到另一个状态j,记为t(i,di)=j

(7)状态转移方程(f)

状态转移方程f描述了状态变量之间的数学关系。一般来说,与最优化问题相应,状态转移方程表示si的值最优化的条件,或者说是状态i所对应问题的最优解值的计算公式,用代数式表示就是:
si=f({(sj,dj)|i=t(j,dj),对决策变量dj所有可行的取值})
2、最优化原理
1951年美国数学家R.Bellman等人,根据一类多阶段问题的特点,把多阶段决策问题变换为一系列互相联系的单阶段问题,然后逐个加以解决。一些静态模型,只要人为地引进“时间”因素,分成时段,就可以转化成多阶段的动态模型,用动态规划方法去处理。与此同时,他提出了解决这类问题的“最优化原理”(Principle of optimality):
“一个过程的最优决策具有这样的性质:即无论其初始状态和初始决策如何,其今后诸策略对以第一个决策所形成的状态作为初始状态的过程而言,必须构成最优策略”。简言之,一个最优策略的子策略,对于它的初态和终态而言也必是最优的。
这个“最优化原理”如果用数学化一点的语言来描述的话,就是:假设为了解决某一优化问题,需要依次作出n个决策D1,D2,…,Dn,如若这个决策序列是最优的,对于任何一个整数k,1 < k < n,不论前面k个决策是怎样的,以后的最优决策只取决于由前面决策所确定的当前状态,即以后的决策Dk+1,Dk+2,…,Dn也是最优的。
最优化原理是动态规划的基础。任何一个问题,如果失去了这个最优化原理的支持,就不可能用动态规划方法计算。
3、什么是动态规划
动态规划是运筹学的一个分支。与其说动态规划是一种算法,不如说是一种思维方法来得更贴切。因为动态规划没有固定的框架,即便是应用到同一道题上,也可以建立多种形式的求解算法。许多隐式图上的算法,例如求单源最短路径的Dijkstra算法、广度优先搜索算法,都渗透着动态规划的思想。还有许多数学问题,表面上看起来与动态规划风马牛不相及,但是其求解思想与动态规划是完全一致的。
因此,动态规划不像深度或广度优先那样可以提供一套模式,需要的时候,取来就可以使用;它必须对具体问题进行具体分析处理,需要丰富的想象力去建立模型,需要创造性的思想去求解。
4、动态规划适于解决什么样的问题
准确地说,动态规划不是万能的,它只适于解决一定条件的最优策略问题。
或许,大家听到这个结论会很失望:其实,这个结论并没有削减动态规划的光辉,因为属于上面范围内的问题极多,还有许多看似不是这个范围中的问题都可以转化成这类问题。
上面所说的“满足一定条件”主要指下面两点:
(1)状态必须满足最优化原理
(2)状态必须满足无后效性

所谓的无后效性是指:“过去的决策只能通过当前状态影响未来的发展,当前的状态是对以往决策的总结”。
这条特征说明什么呢?它说明动态规划适于解决当前决策和过去状态无关的问题。状态,出现在策略的任何一个位置,它的地位都是相同的,都可以实施同样的决策。这就是无后效性的内涵。 
5、用动态规划解题的好处
说了这么多的动态规划,它到底给我们解题能带来什么好处呢?

其实动态规划的最大优势在于它具有极高的效率,而且动态规划还有其他的优势,例如:动态规划可以得出一系列解,算法清晰简便,程序易编、易调,等等。


最优化原理与无后效性

上面已经介绍了动态规划模型的基本组成,现在需要解决的问题是:什么样的“多阶段决策问题”才可以采用动态规划的方法求解?
一般来说,能够采用动态规划方法求解的问题必须满足.最优化原理.无后效性原则

(1)动态规划的最优化原理。作为整个过程的最优策略具有如下性质:无论过去的状态和决策如何,对前面的决策所形成的当前状态而言,余下的诸决策必须构成最优策略。
可以通俗地理解为子问题的局部最优将导致整个问题的全局最优,即问题具有最优子结构的性质,也就是说一个问题的最优解只取决于其子问题的最优解,非最优解对问题的求解没有影响。在例题1最短路径问题中,A到E的最优路径上的任一点到终点E的路径也必然是该点到终点E的一条最优路径,满足最优化原理。下面来讨论另外一个问题。
【例题2】余数最少的路径。

如图所示,有4个点,分别是A、B、C、D,相邻两点用两条连线C2k,C2k-1(1≤k≤3)表示两条通行的道路。连线上的数字表示道路的长度。定义从A到D的所有路径中,长度除以4所得余数最小的路径为最优路径。
求一条最优路径。

【分析】在这个问题中,如果还按照例题1中的方法去求解就会发生错误。按照例题1的思想,A的最优取值可以由B的最优取值来确定,而B的最优取值为(1+3) mod 4 = 0,所以A的最优值应为2,而实际上,路径C1-C3-C5可得最优值为(2+1+1) mod 4 = 0,所以,B的最优路径并不是A的最优路径的子路径,也就是说,A的最优取值不是由B的最优取值决定的,即其不满足最优化原理,问题不具有最优子结构的性质。
由此可见,并不是所有的“决策问题”都可以用“动态规划”来解决,运用“动态规划”来处理问题必须满足最优化原理

(2)动态规划的无后效性原则所谓无后效性原则,指的是这样一种性质:某阶段的状态一旦确定,则此后过程的演变不再受此前各状态及决策的影响。也就是说,“未来与过去无关”,当前的状态是此前历史的一个完整总结,此前的历史只能通过当前的状态去影响过程未来的演变。具体地说,如果一个问题被划分各个阶段之后,阶段 I 中的状态只能由阶段 I+1 中的状态通过状态转移方程得来,与其他状态没有关系,特别是与未发生的状态没有关系,这就是无后效性。从图论的角度去考虑,如果把这个问题中的状态定义成图中的顶点,两个状态之间的转移定义为边,转移过程中的权值增量定义为边的权值,则构成一个有向无环加权图,因此,这个图可以进行“拓扑排序”,至少可以按他们拓扑排序的顺序去划分阶段。
看一看下面的两个具体例子。
【例题3】货郎担问题。对于平面给定的n个点,编程确定一条连结各点的、闭合的游历路线问题。图中给出了7个点的情况问题的解。
【例题4】旅行路线问题。在货郎担问题的基础上,若规定这种游历路线先从最左边开始,严格地由左至右到最右边的点,然后再严格地由右至左到出发点,求整个路程最短的路径长度。图中给出了7个点问题的解。

例3图 货郎担问题
例4图 旅行路线图

【分析】这两个问题看起来很非常相似,但本质上是完全不同的。为了方便讨论,可以将每个顶点标记号码。由于必然经过最右边的顶点7,所以一条路(P1-P2)可以看做两条路(P1-7)与(P2-7)的结合。因此,这个题目的状态可以用两条道路结合的形式表示。可以把这些状态中,两条路中起始顶点相同的状态归于一个阶段,设为阶段[P1,P2]。
那么,对于旅行路线问题来说,阶段[P1,P2]如果可以由阶段[Q1,Q2]推出,则必须满足的条件就是:Pl < Q1或P2 < Q2。例如,阶段[3,4]中的道路可以由阶段[3,5]中的道路加一条边4—5得出,而阶段[3,5]的状态却无法由阶段[3,4]中的状态得出,因为在旅行路线问题的要求中必须严格地由左到右来旅行。所以如果已经知道了阶段[3,4]中的状态,则阶段[3,5]中的状态必然已知,因此,问题满足无后效性原则,可以考虑用动态规划方法求解。

而对于货郎担问题,阶段与阶段之间没有什么必然的“顺序”。如道路{3—2—5—7,4—6—7}属于阶段[3,4],可由属于阶段[2,4]的道路{2—5—7,4—6—7}推出;而道路{2—3—6—7,4—5—7}属于阶段[2,4],可由属于阶段[3,4]的道路{3—6—7,4—5—7}推出。如果以顶点表示阶段,推出关系表示边,那么,阶段[3,4]与阶段[2,4]对应的关系就如图右所示。可以很清晰地看出,这两个阶段的关系是“有后效性”的。因为这个图中存在“环路”。对于这个问题是不能像上一个问题那样来解决的。
阶段关系图

动态规划的逆向思维法

动态规划是一种思维方法,没有统一的、具体的模式。动态规划可以从多方面去考察,不同的方面对动态规划有不同的表述。我们不打算强加一种统一的表述,而是从多个角度对动态规划的思维方法进行讨论,希望大家在思维具体问题时,也能够从多个角度展开,这样收获会更大。
逆向思维法是指从问题目标状态出发倒推回初始状态或边界状态的思维方法。如果原问题可以分解成几个本质相同、规模较小的问题,很自然就会联想到从逆向思维的角度寻求问题的解决。
你也许会想,这种将大问题分解成小问题的思维不就是分治法吗?动态规划是不是分而治之呢?其实,虽然我们在运用动态规划的逆向思维法和分治法分析问题时,都使用了这种将问题实例归纳为更小的、相似的子问题,并通过求解子问题产生一个全局最优值的思路,但动态规划不是分治法:关键在于分解出来的各个子问题的性质不同。
分治法要求各个子问题是独立的(即不包含公共的子问题),因此一旦递归地求出各个子问题的解后,便可自下而上地将子问题的解合并成原问题的解。如果各子问题是不独立的,那么分治法就要做许多不必要的工作,重复地解公共的子问题。
动态规划与分治法的不同之处在于动态规划允许这些子问题不独立(即各子问题可包含公共的子问题),它对每个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。这就是动态规划高效的一个原因。
动态规划的逆向思维法的要点可归纳为以下三个步骤:
(1)分析最优值的结构,刻画其结构特征;
(2)递归地定义最优值;
(3)按自底向上或自顶向下记忆化的方式计算最优值。


动态规划的正向思维法

正向思维法是指从初始状态或边界状态出发,利用某种规则不断到达新的状态,直到问题目标状态的方法。动态规划的正向思维法,正是从已知最优值的初始状态或边界状态开始,按照一定的次序遍历整个状态空间,递推出每个状态所对应问题的最优值。
提出动态规划的正向思维法的根本原因,是为了摆脱逆向思维法当中那种将大问题转化为子问题的思维框框,提供一种新的思维方式。在正向思维法中,我们不再区分原问题和子问题,将动态规划的过程看成是从状态到状态的转移。我们将所有的状态构造出一个状态空间,并在状态空间中设想一个状态网络,若对两个状态i,j,存在决策变量di使t(i,di)=j,则向状态网络添加有向边。给定己知最优值的初始状态或边界状态,我们可以沿着有向边推广到未知最优值的新状态,利用状态转移方程得到新状态的状态变量的最优值。我们可以用这种方式遍历整个状态空间,得到每个状态的状态变量的最优值。
因为正向思维法中不再区分原问题、子问题、子子问题,所以我们不再按照问题被递归调用求解的相反次序的方法确定状态最优值的计算次序。从上面我们知道可以按照状态的拓扑序列来计算每个状态的最优值,于是我们用一个新的名词“阶段”来描述在状态空间遍历的过程中,各个状态最优值的计算次序。我们将每个状态和一个阶段挂钩,前一个阶段的状态先计算,后一个阶段的状态后计算。有的时候我们甚至将一组状态和一个阶段挂钩,前一个阶段的那组状态先计算,后一个阶段的那组状态后计算,而在同一个阶段内,那些状态的计算次序可以是任意的。
动态规划的正向思维法的要点可归纳为以下三个步骤:
(1)构造状态网络;
(2)根据状态转移关系和状态转移方程建立最优值的递推计算式:
(3)按阶段的先后次序计算每个状态的最优值。
动态规划的正向思维法带给我们什么启示呢?动态规划需要按阶段遍历整个状态空间,因此动态规划的效率取决于状态空间的大小和计算每个状态最优值的开销:如果状态空间的大小是多项式的,那么应用动态规划的算法就是多项式时间的;如果状态空间的大小是指数的,那么应用动态规划的算法也是指数时间的。因此,找一个好的状态划分对动态规划的效率是至关重要的。
将这个结论应用到逆向思维上,我们得出如下结果:一个问题的最优子结构常常暗示了动态规划的状态空间。典型的情况是,某一个特定问题可有几类“自然”的子问题,不同的子问题往往意味着不同的最优子结构,从而我们得到不同的状态划分方案。但是由这些不同的状态得到的算法的效率可能差异极大。例如,某个问题的输入是一个有序序列,有两类“自然”的子问题,一类子问题的输入是原问题输入序列的所有子序列,另一类子问题的输入是原问题输入序列的任意元素构成的新序列。显然若我们采用后者的最优子结构来建立状态,它的状态空间必然远远大于基于前者的状态空间。那末基于后者的状态空间的动态规划则要解许多不必要的问题,使得算法的效率骤然下降。
从动态规划的正向思维法的分析可以看出,我们从已知最优值的初始状态和边界状态出发,利用最优化原理,一步一步向未知的目标状态推进,直到目标状态的最优值解决。这种“从己知推广到未知”的思维,正是动态规划正向思维法的精髓。大家在运用动态规划的正向思维法时如果能掌握这一点,那么就能达到应用自如的境界。
在应用动态规划求解的问题的过程中,希望读者能够注意从题目的分析中领会:应用动态规划解题是富于技巧和创造性的,没有固定的模式可套;题目出现的形式多种多样,而且大部分表面上与动态规划看不出直接的联系。只有在充分把握其思想精髓的前提下大胆联想,才能达到得心应手,灵活运用的境界。


动态规划设计方法的一般模式

动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。如图所示。动态规划的设计都有着一定的模式,一般要经历以下几个步骤。

     ┌───┐ ┌───┐   ┌───┐初始状态→│决策1│→│决策2│→…→│决策n│→结束状态     └───┘ └───┘   └───┘               图1 动态规划决策过程示意图
(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。
(2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
(3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两段各状态之间的关系来确定决策。
(4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
(5)程序设计实现:动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。

根据上述动态规划设计的步骤,可得到大体解题框架如图2所示。

          图2 动态规划设计的一般模式
上述提供了动态规划方法的一般模式,对于简单的动态规划问题,可以按部就班地进行动态规划的设计。
下面,给出一个利用动态规划方法求解的典型例子。 
【例题6】数字三角形问题。图3示出了一个数字三角形宝塔。数字三角形中的数字为不超过100的整数。现规定从最顶层走到最底层,每一步可沿左斜线向下或右斜线向下走。
任务一:假设三角形行数≤10,键盘输入一个确定的整数值M,编程确定是否存在一条路径,使得沿着该路径所经过的数字的总和恰为M,若存在则给出所有路径,若不存在,则输出“NO Answer!”字样。
任务二:假设三角形行数≤100,编程求解从最顶层走到最底层的一条路径,使得沿着该路径所经过的数字的总和最大,输出最大值。
输人数据:由文件输入数据,任务一中文件第一行是三角形的行数N和整数值M。以后的N行分别是从最顶层到最底层的每一层中的数字。任务二中文件数据格式同任务一,只是第一行中没有整数值M。在例子中任务二的文件数据表示如下:
输入:     7             输出:    3 8          输出路径和最大值   8 1 0         或“No Answer!”字样。  2 7 7 4  4 5 2 6 5 图3  数字三角形
【分析】对于这一问题,很容易想到用枚举的方法去解决,即列举出所有路径并记录每一条路径所经过的数字总和。然后判断数字总和是否等于给定的整数值M或寻找出最大的数字总和,这一想法很直观,而且对于任务一,由于数字三角形的行数不大(<=10),因此其枚举量不是很大,应该能够实现。但对于任务二,如果用枚举的方法,当三角形的行数等于100时,其枚举量之大是可想而知的,显然,枚举法对于任务二的求解并不适用。其实,只要对对任务二稍加分析,就可以得出一个结论:
如果得到一条由顶至底的某处的一条最佳路径,那么对于该路径上的每一个中间点来说,由顶至该中间点的路径所经过的数字和也为最大。因此该问题是一个典型的多阶段决策最优化的问题。算法设计与分析如下:
对于任务一,合理地确认枚举的方法,可以优化问题的解法。由于从塔顶到底层每次都只有两种走法,即左或右。设“0”表示左,“1”表示右,对于层数为N的数字塔,从顶到底的一种走法可用一个N-1位的二进制数表示。如例中二进制数字串1011,其对应的路径应该是:8—1—4—6。这样就可以用一个N—l位的二进制数来模拟走法和确定解的范围。穷举出从0到2n-1个十进制数所对应的N-1位二进制串对应的路径中的数字总和,判定其是否等于M而求得问题的解。
对于任务二,采用动态规划中的顺推解法。按三角形的行划分阶段,若行数为n,则可把问题看做一个n-1个阶段的决策问题。从始点出发,依顺向求出第一阶段、第二阶段……第n—1阶段中各决策点至始点的最佳路径,最终求出始点到终点的最佳路径。
设:fk(Uk)为从第k阶段中的点Uk至三角形顶点有一条最佳路径,该路径所经过的数字的总和最大,fk(Uk)表示为这个数字和;
由于每一次决策有两个选择,或沿左斜线向下,或沿右斜线向下,因此设:
Uk1为k-1阶段中某点Uk沿左斜线向下的点;
Uk2为k-1阶段中某点Uk沿右斜线向下的点;
dk(Uk1)为k阶段中Uk1的数字;dk(Uk2)为k阶段中Uk2的数字。
因而可写出顺推关系式(状态转移方程)为:
fk(Uk)=max{fk-1(Uk)+dk(Uk1),fk-1(Uk)+dk(Uk2)}(k=1,2,3,…,n)
f0(U0)=0
经过一次顺推,便可分别求出由顶至底N个数的N条路径,在这N条路径所经过的N个数字和中,最大值即为正确答案。


动态规划与静态规划的关系

动态规划与静态规划(线性和非线性规划等)研究的对象本质上都是在若干约束条件下的函数极值问题。两种规划在很多情况下原则上可以相互转换。

动态规划可以看作求决策u1,u2,...,un,使指标函数V1n(xl,u1,u2,...,un)达到最优(最大或最小)的极值问题,状态转移方程、端点条件以及允许状态集、允许决策集等是约束条件,原则上可以用非线性规划方法求解。

一些静态规划只要适当引入阶段变量、状态、决策等就可以用动态规划方法求解。下面用例子说明:

[例8] 用动态规划解下列非线性规划:

其中gk(uk)为任意的已知函数。

解:按变量uk的序号k划分阶段,看作n段决策过程;设状态为x1,x2,..xn,取问题中的变量u1,u2,..,un为决策;状态转移方程为:

取gk(uk)为阶段指标,最优值函数的基本方程为(注意到xn+1=0):

解此动态规划即可得到原静态规划的解。

上面这个静态规划的模型有很多实际应用,比如下面这个问题:

[例9] Inflate

The more points students score in our contests, the happier we here at the USACO are. We try to design our contests so that people can score as many points as possible, and would like your assistance.

We have several categories from which problems can be chosen, where a "category" is an unlimited set of contest problems which all require the same amount of time to solve and deserve the same number of points for a correct solution. Your task is write a program which tells the USACO staff how many problems from each category to include in a contest so as to maximize the total number of points in the chosen problems while keeping the total solution time within the length of the contest.

The input includes the length of the contest, M (1 <= M <= 10,000) (don't worry, you won't have to compete in the longer contests until training camp) and N, the number of problem categories, where 1 <= N <= 10,000.

Each of the subsequent N lines contains two integers describing a category: the first integer tells the number of points a problem from that category is worth (1 <= points <= 10000); the second tells the number of minutes a problem from that category takes to solve (1 <= minutes <= 10000).

Your program should determine the number of problems we should take from each category to make the highest-scoring contest solvable within the length of the contest. Remember, the number from any category can be any nonnegative integer (0, one, or many). Calculate the maximum number of possible points.

PROGRAM NAME: inflate

INPUT FORMAT
Line 1: M, N -- contest minutes and number of problem classes
Lines 2-N+1: Two integers: the points and minutes for each class


SAMPLE INPUT (file inflate.in)
300 4
100 60
250 120
120 100
35 20

OUTPUT FORMAT
A single line with the maximum number of points possible given the constraints.

SAMPLE OUTPUT (file inflate.out)
605

显而易见,上面这个例题的数学模型就是例8的规划模型。

与静态规划相比,动态规划的优越性在于:

  1. 能够得到全局最优解。由于约束条件确定的约束集合往往很复杂,即使指标函数较简单,用非线性规划方法也很难求出全局最优解。而动态规划方法把全过程化为一系列结构相似的子问题,每个子间题的变量个数大大减少,约束集合也简单得多,易于得到全局最优解。特别是对于约束集合、状态转移和指标函数不能用分析形式给出的优化问题,可以对每个子过程用枚举法求解,而约束条件越多,决策的搜索范围越小,求解也越容易。对于这类问题,动态规划通常是求全局最优解的唯一方法。
  2. 可以得到一族最优解。与非线性规划只能得到全过程的一个最优解不同,动态规划得到的是全过程及所有后部子过程的各个状态的一族最优解。有些实际问题需要这样的解族,即使不需要,它们在分析最优策略和最优值对于状态的稳定性时也是很有用的。当最优策略由于某些原因不能实现时,这样的解族可以用来寻找次优策略。
  3. 能够利用经验提高求解效率。如果实际问题本身就是动态的,由于动态规划方法反映了过程逐段演变的前后联系和动态特征,在计算中可以利用实际知识和经验提高求解效率。比如在策略迭代法中,实际经验能够帮助选择较好的初始策略,提高收敛速度。

动态规划的主要缺点是:

  1. 没有统一的标准模型,也没有构造模型的通用方法,甚至还没有判断一个问题能否构造动态规划模型的具体准则(大部分情况只能够凭经验判断是否适用动态规划)。这样就只能对每类问题进行具体分析,构造具体的模型。对于较复杂的问题在选择状态、决策、确定状态转移规律等方面需要丰富的想象力和灵活的技巧性,这就带来了应用上的局限性。
  2. 用数值方法求解时存在维数灾难(curse of dimensionality)。若一维状态变量有m个取值,那么对于n维问题,状态xk就有mn个值,对于每个状态值都要计算、存储函数fk(xk),对于n稍大(即使n=3)的实际问题的计算往往是不现实的。目前还没有克服维数灾难的有效的一般方法。

动态规划与递推——动态规划是最优化算法

动态规划的实质是分治和解决冗余,因此动态规划也是递归思想的应用之一。但是,动态规划和递归法还是有区别的。一般我们在实际应用中遇到的问题主要分为四类:判定性问题、构造性问题、计数问题和最优化问题。动态规划是解决最优化问题的有效途径,而递推法在处理判定性问题和计数问题方面是一把利器。下面分别就两个例子,谈一下递推法和动态规划在这两个方面的联系。

[例如]模4最优路径问题(参见例题2)

在下图中找出从第1点到第4点的一条路径,要求路径长度mod 4的余数最小。

这个图是一个多段图,而且是一个特殊的多段图。虽然这个图的形式比一般的多段图要简单,但是这个最优路径问题却不能用动态规划来做。因为一条从第1点到第4点的最优路径,在它走到第2点、第3点时,路径长度mod 4的余数不一定是最小,也就是说最优策略的子策略不一定最优——这个问题不满足最优化原理。

但是我们可以把它转换成判定性问题,用递推法来解决。判断从第1点到第k点的长度mod 4为sk的路径是否存在,用fk(sk)来表示,则递推公式如下:

边界条件为

这里lenk,i表示从第k-1点到第k点之间的第i条边的长度,方括号表示“或(or)”运算。最后的结果就是可以使f4(s4)值为真的最小的s4值。

这个递推法的递推公式和动态规划的规划方程非常相似,我们在这里借用了动态规划的符号也就是为了更清楚地显示这一点。其实它们的思想也是非常相像的,可以说是递推法借用了动态规划的思想解决了动态规划不能解决的问题。

有的多阶段决策问题(像这一题的阶段特征就很明显),由于不能满足最优化原理等使用动态规划的先决条件,而无法应用动态规划。在这时可以将最优指标函数的值当作“状态”放到下标中去,从而变最优化问题为判定性问题,再借用动态规划的思想,用递推法来解决问题。

[例10]钉子与小球 (NOI'99)

有一个三角形木板,竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如下图a)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。

让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图b就是小球一条可能的路径。

我们知道小球落在第i个格子中的概率为:

其中i为格子的编号,从左至右依次为0,1,...,n。

现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。

图a图b图c

输入:

第1行为整数n(2<=n<=50)和m(0<=m<=n)。

以下n行依次为木板上从上至下n行钉子的信息,每行中‘ * ’表示钉子还在,‘ . ’表示钉子被拔去,注意在这n行中空格符可能出现在任何位置。

输出:

仅一行,是一个既约分数(0写成0/1),为小球落在编号为m的格子中的概率pm

既约分数的定义:A/B是既约分数,当且仅当A、B为正整数且A和B没有大于1的公因子。

样例输入:

5 2** .* * ** . * ** * * * *

样例输出:

7/16

这个题目一看就不觉让人想起一道经典的动态规划题。下面先让我们回顾一下这个问题。

[例11]数字三角形(IOI'94)

在下图中求从顶至低某处的一条路径,使该路径所经过的数字的总和最大,每一步只能向左下或右下走。

7

3  8

8  1  0

2  7  4  4

4  5  2  6  5

在这个问题中,我们按走过的行数来划分阶段,以走到每一行时所在的位置来作为状态,决策就是向左下走(用0表示)或向右下走(用1表示)。

状态转移方程:

规划方程:

边界条件:

这是一个比较简单的最优化问题,我们还可以把这个问题改成一个更加简单的整数统计问题:求顶点到每一点的路径总数。把这个总数用fk(xk)表示,那么递推公式就是:

在这里,虽然求和公式只有两项,但我们仍然用∑的形式表示,就是为了突出这个递推公式和上面的规划方程的相似之处。这两个公式的边界条件都是一模一样的。

再回到我们上面的“钉子与小球”问题,这是一个概率统计问题。我们继续沿用上面的思想,用fk(xk)表示小球落到第k行第xk个钉子上的概率,则递推公式如下:

这里函数Existk(xk)表示第k行第xk个钉子是否存在,存在则取1,不存在则取0;

边界条件

可以看出这个公式较之上面的两个式子虽然略有变化,但是其基本思想还是类似的。在解这个问题的过程中,我们再次运用了动态规划的思想。

一般说来,很多最优化问题都有着对应的计数问题;反过来,很多计数问题也有着对应的最优化问题。因此,我们在遇到这两类问题时,不妨多联系、多发展,举一反三,从比较中更深入地理解动态规划的思想。


动态规划与搜索——动态规划是高效率、高消费算法

同样是解决最优化问题,有的题目我们采用动态规划,而有的题目我们则需要用搜索。这其中有没有什么规则呢?

我们知道,撇开时空效率的因素不谈,在解决最优化问题的算法中,搜索可以说是“万能”的。所以动态规划可以解决的问题,搜索也一定可以解决。

把一个动态规划算法改写成搜索是非常方便的,状态转移方程、规划方程以及边界条件都可以直接“移植”,所不同的只是求解顺序。动态规划是自底向上的递推求解,而搜索则是自顶向下的递归求解(这里指深度搜索,宽度搜索类似)。

反过来,我们也可以把搜索算法改写成动态规划。状态空间搜索实际上是对隐式图中的点进行枚举,这种枚举是自顶向下的。如果把枚举的顺序反过来,变成自底向上,那么就成了动态规划。(当然这里有个条件,即隐式图中的点是可排序的)

正因为动态规划和搜索有着求解顺序上的不同,这也造成了它们时间效率上的差别。在搜索中,往往会出现下面的情况:

对于上图(a)这样几个状态构成的一个隐式图,用搜索算法就会出现重复,如上图(b)所示,状态C2被搜索了两次。在深度搜索中,这样的重复会引起以C2为根整个的整个子搜索树的重复搜索;在宽度搜索中,虽然这样的重复可以立即被排除,但是其时间代价也是不小的。而动态规划就没有这个问题,如上图(c)所示。

一般说来,动态规划算法在时间效率上的优势是搜索无法比拟的。(当然对于某些题目,根本不会出现状态的重复,这样搜索和动态规划的速度就没有差别了。)而从理论上讲,任何拓扑有序(现实中这个条件常常可以满足)的隐式图中的搜索算法都可以改写成动态规划。但事实上,在很多情况下我们仍然不得不采用搜索算法。那么,动态规划算法在实现上还有什么障碍吗?

考虑上图(a)所示的隐式图,其中存在两个从初始状态无法达到的状态。在搜索算法中,这样的两个状态就不被考虑了,如上图(b)所示。但是动态规划由于是自底向上求解,所以就无法估计到这一点,因而遍历了全部的状态,如上图(c)所示。

一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。

如何协调好动态规划的高效率与高消费之间的矛盾呢?有一种折衷的办法就是记忆化算法(备忘录法)。记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了。这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。


动态规划与网络流——动态规划是易设计易实现的算法

由于图的关系复杂而无序,一般难以呈现阶段特征,因此动态规划在图论中的应用不多。但有一类图,它的点却是有序的,这就是无环有向图。

在有向无环图中,我们可以对点进行拓扑排序,使其体现出有序的特征,从而据此划分阶段。在有向无环图中求最短路径的算法,已经体现出了简单的动态规划思想。请看下面的例子。

[例12] 单源最短路径问题

已知从A到J的路线及费用如上图,求从A到J的最小费用路线。

问题的分析和解答:

本问题没有明显的阶段划分,各点间没有一定的先后次序,不能按照最少步数来决定顺序,如从A到D走捷径需4,但A-C-D只需3,更优。看来图中出现回路,不能实施动态规划。其实不然。细想一下,从A到J的最优策略,它每一部分也是最优的(可以用反证法来证明),换言之,本题也具有最优化性质,只是阶段不明显而已。

对于这类问题,我们可以换个角度分析,构造算法。比较一下前面所讲的动态规划法,都是以某个状态为终点,寻找到达次点的路径,然后比较优劣,确定此状态最优值。可是,本题阶段不明显,各状态之间的道路会出现嵌套,故此法不能使用。变一下角度,每次都以某个状态为起点,遍历由它引申出去的路径,等所有已知状态都扩展完了,再来比较所有新状态,把值最小的那个状态确定下来,其它的不动。如上图,先从A出发,找到3个结点B,D,C,费用为F(B)=3,F(D)=4,F(C)=2。因为F(B),F(D)都大于F(C),那么可以确定:不可能再有路线从B或D出发到C,比A-C更优。这样F(C)的最优值便确定了。可是,有没有路线从C出发到B或D,比A-B或A-D更优呢?还不清楚。继续下去,因为A扩展完了,只有从C开始,得到A-C-D=3,A-C-F=3,于是F(D)的值被刷新了,等于3。现在,有F(B)=F(D)=F(F)=3,于是,三点的最优值都确定下来了。然后以分别以三个点为起点,继续找。以此类推,直到J点的最优值确定为止。

细心观察,其实本题的隐含阶段就是以各结点的最优值的大小来划分的,上述过程就是按最优值从小到大运用动态规划。人们习惯上把此题归入到图论范畴中,并将上述方法称为标号法。这个算法就是图论中著名的Dijkstra单源最短路径算法

事实上,动态规划在图论中还有更多的应用,请看下例:

[例13]  N个人的街道问题

在街道问题中,若有N个人要从左下角走向右上角,要求他们走过的边的总长度最大。当然,这里每个人也只能向右或向上走。下面是一个样例,左图是从出发地到目的地的三条路径,右图是他们所走过的边,这些边的总长度为5 + 4 + 3 + 6 + 3 + 3 + 5 + 8 + 8 + 7 + 4 + 5 + 9 + 5 + 3 = 78(不一定是最大)。

这个题目是对街道问题的又一次扩展。仿照街道问题的解题方法,我们仍然可以用动态规划来解决本题。不过这一次是N个人同时走,状态变量也就需要用N维向量来表示。相应的,决策变量也要变成N维向量:

状态转移方程不需要做什么改动:

在写规划方程时,需要注意在第k阶段,N条路径所走过的边的总长度的计算,在这里用来表示了:

边界条件为

可见将原来的动态规划算法移植到这个问题上来,在理论上还是完全可行的。但是,现在的这个动态规划算法的时空复杂度已经是关于N的指数函数,只要N稍微大一点,这个算法就不可能实现了。

下面我们换一个思路,将N条路径看成是网络中一个流量为N的流,这样求解的目标就是使这个流的费用最大。但是本题又不同于一般的费用流问题,在每一条边e上的流费用并不是流量和边权的乘积,而是用下式计算:

为了使经典的费用流算法适用于本题,需要将模型稍微转化一下:

如图,将每条边拆成两条,拆开后一条边上有权w0,但是容量限制为1;另一条边没有容量限制,但是流过这条边就不计费用。这样我们就把问题转化成了一个标准的最大费用固定流问题。

这个算法可以套用经典的最小费用最大流算法,在此就不细说了。

IOI97的“障碍物探测器”比这一题要复杂一些,但是基本思想是相似的。类似的题目还有99年冬令营的“迷宫改造”。从这些题目中都可以看到动态规划和网络流的联系。

推广到一般情况,任何有向无环图中的费用流问题在理论上说,都可以用动态规划来解决。对于流量为N(如果流量不固定,这个N需要事先求出来)的费用流问题,用N维的向量xk=(xk,1,xk,2,…,xk,N)来描述状态,其中xk,i∈V , 1≤i≤N 。相应的,决策也用N维的向量uk=(uk,1,uk,2,…,uk,N)来表示,其中uk,i∈E(xk,i) , 1≤i≤N ,E(v)表示指向v的弧集。则状态转移方程可以这样表示:

规划方程为

边界条件为

在大多数情况下,动态规划的实现比网络流要简单的多。但是,由于N维动态规划算法是指数级算法,因而在实现中的局限性很大,仅可用于一些N非常小的题目适用。

0 0
原创粉丝点击