动态规划学习资料.docx
- 文档编号:10566884
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:35
- 大小:116.14KB
动态规划学习资料.docx
《动态规划学习资料.docx》由会员分享,可在线阅读,更多相关《动态规划学习资料.docx(35页珍藏版)》请在冰豆网上搜索。
动态规划学习资料
动态规划基本原理
动态规划(dynamicprogramming)是运筹学的一个分支,是求解决策过程(decisionprocess)最优化的数学方法。
20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistepdecisionprocess)的优化问题时,提出了著名的最优化原理(principleofoptimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
近年来,涉及动态规划的各种竞赛题越来越多,每一年的NOI几乎都至少有一道题目需要用动态规划的方法来解决;而竞赛对选手运用动态规划知识的要求也越来越高,已经不再停留于简单的递推和建模上了。
要了解动态规划的概念,首先要知道什么是多阶段决策问题。
一、多阶段决策问题
如果一类活动过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策(采取措施),一个阶段的决策确定以后,常常影响到下一个阶段的决策,从而就完全确定了一个过程的活动路线,则称它为多阶段决策问题。
各个阶段的决策构成一个决策序列,称为一个策略。
每一个阶段都有若干个决策可供选择,因而就有许多策略供我们选取,对应于一个策略可以确定活动的效果,这个效果可以用数量来确定。
策略不同,效果也不同,多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果.
让我们先来看下面的例子:
如图所示的是一个带权有向的多段图,要求从A到D的最短路径的长度(下面简称最短距离)。
我们可以搜索,枚举图中的每条路径,但当图的规模大起来时,搜索的效率显然不可能尽人意。
让我们来试用动态规划的思路分析这道题:
从图中可以看到,A点要到达D点必然要经过B1和B2中的一个,所以A到D的最短距离必然等于B1到D的最短距离加上5,或是B2到D的最短距离加上2。
同样的,B1到D的最短距离必然等于C1到D的最短距离加上3或是C2到D的最短距离加上2,……。
我们设G[i]为点i到点D的距离,显然G[C1]=4,G[C2]=3,G[C3]=5,根据上面的分析,有:
G[B1]=min{G[C1]+3,G[C2]+2}=5,
G[B2]=min{G[C2]+7,G[C3]+4}=9,
再就有G[A]=min{G[B1]+5,G[B2]+2}=10,
所以A到D的最短距离是10,最短路径是AB1C2D。
二、动态规划的术语
1.阶段
把所给求解问题的过程恰当地分成若干个相互联系的阶段,以便于求解,过程不同,阶段数就可能不同.描述阶段的变量称为阶段变量。
在多数情况下,阶段变量是离散的,用k表示。
此外,也有阶段变量是连续的情形。
如果过程可以在任何时刻作出决策,且在任意两个不同的时刻之间允许有无穷多个决策时,阶段变量就是连续的。
在前面的例子中,第一个阶段就是点A,而第二个阶段就是点A到点B,第三个阶段是点B到点C,而第四个阶段是点C到点D。
2.状态
状态表示每个阶段开始面临的自然状况或客观条件,它不以人们的主观意志为转移,也称为不可控因素。
在上面的例子中状态就是某阶段的出发位置,它既是该阶段某路的起点,同时又是前一阶段某支路的终点。
在前面的例子中,第一个阶段有一个状态即A,而第二个阶段有两个状态B1和B2,第三个阶段是三个状态C1,C2和C3,而第四个阶段又是一个状态D。
过程的状态通常可以用一个或一组数来描述,称为状态变量。
一般,状态是离散的,但有时为了方便也将状态取成连续的。
当然,在现实生活中,由于变量形式的限制,所有的状态都是离散的,但从分析的观点,有时将状态作为连续的处理将会有很大的好处。
此外,状态可以有多个分量(多维情形),因而用向量来代表;而且在每个阶段的状态维数可以不同。
当过程按所有可能不同的方式发展时,过程各段的状态变量将在某一确定的范围内取值。
状态变量取值的集合称为状态集合。
3.无后效性
我们要求状态具有下面的性质:
如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响,所有各阶段都确定时,整个过程也就确定了。
换句话说,过程的每一次实现可以用一个状态序列表示,在前面的例子中每阶段的状态是该线路的始点,确定了这些点的序列,整个线路也就完全确定。
从某一阶段以后的线路开始,当这段的始点给定时,不受以前线路(所通过的点)的影响。
状态的这个性质意味着过程的历史只能通过当前的状态去影响它的未来的发展,这个性质称为无后效性。
4.决策
一个阶段的状态给定以后,从该状态演变到下一阶段某个状态的一种选择(行动)称为决策。
在最优控制中,也称为控制。
在许多问题中,决策可以自然而然地表示为一个数或一组数。
不同的决策对应着不同的数值。
描述决策的变量称决策变量,因状态满足无后效性,故在每个阶段选择决策时只需考虑当前的状态而无须考虑过程的历史。
决策变量的范围称为允许决策集合。
5.策略
由每个阶段的决策组成的序列称为策略。
对于每一个实际的多阶段决策过程,可供选取的策略有一定的范围限制,这个范围称为允许策略集合。
允许策略集合中达到最优效果的策略称为最优策略。
给定k阶段状态变量x(k)的值后,如果这一阶段的决策变量一经确定,第k+1阶段的状态变量x(k+1)也就完全确定,即x(k+1)的值随x(k)和第k阶段的决策u(k)的值变化而变化,那么可以把这一关系看成(x(k),u(k))与x(k+1)确定的对应关系,用x(k+1)=Tk(x(k),u(k))表示。
这是从k阶段到k+1阶段的状态转移规律,称为状态转移方程。
6.最优性原理
作为整个过程的最优策略,它满足:
相对前面决策所形成的状态而言,余下的子策略必然构成“最优子策略”。
最优性原理实际上是要求问题的最优策略的子策略也是最优。
让我们通过对前面的例子再分析来具体说明这一点:
从A到D,我们知道,最短路径是AB1C2D,这些点的选择构成了这个例子的最优策略,根据最优性原理,这个策略的每个子策略应是最优:
AB1C2是A到C2的最短路径,B1C2D也是B1到D的最短路径……事实正是如此,因此我们认为这个例子满足最优性原理的要求。
三、动态规划例子
例1:
数字三角形
【问题描述】 图示出了一个数字三角形。
请编一个程序计算从顶至底的某处的一条路径,使该路径所经过的数字的总和最大。
●每一步可沿左斜线向下或右斜线向下走;
●1<三角形行数≤100;
●三角形中的数字为整数0,1,…99;
【输入数据:
】
由INPUT.TXT文件中首先读到的是三角形的行数。
在例子中INPUT.TXT表示如下:
5
7
38
810
2744
45265
【输出数据:
】
把最大总和(整数)写入OUTPUT.TXT文件。
上例为:
30
【分析:
】
只要对该题稍加分析,就可以得出一个结论:
如果得到一条由顶至底的某处的一条最佳路径,那么对于该路径上的每一个中间点来说,由顶至该中间点的路径所经过的数字和也为最大。
因此该题是一个典型的多阶段决策最优化的问题。
我们采用动态规划中的顺推解法。
按三角形的行划分阶段。
若行数为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)}
f0(U0)=0;
K=1,2,3,4,……n
即:
F[I,j]=max(f[i-1,j]+d[I,j],f[i-1,j-1]+d[I,j])
边界条件:
f[1,1]=d[1,1]
经过一次顺推,便可分别求出由顶至底N个数的N条路径,在这N条路径所经过的N个数字和中,最大值即为正确答案。
【参考程序】
ProgramP1;
Const
Maxn=100;
Type
Node=Record
Val,Tot:
Integer
{当前格数字;从[1,1]到当前格的路径所经过的数字和}
End;
VarList:
Array[1..Maxn,1..Maxn]ofNode;{计算表}
N,Max,{行数,最大总和}
I,J:
Integer;{辅助变量}
ProcedureInit;
Begin
Readln(N);{读三角形行数}
Fori:
=1toNDo{读入三角形各格的数字}
Forj:
=1toiDo
Read(List[i,j].Val);
End; {init}
ProcedureMain;
Begin
List[1,1].Tot:
=List[1,1].Val;{从[1,1]位置开始往下顺推}
Fori:
=2toNDo
Forj:
=1toiDo
Begin
List[i,j].Tot:
=-1;{从[1,1]至[i,j]的数字和初始化}
If(j<>1)And(List[i-1,j-1].Tot+List[i,j].Val>List[i,j].Tot)ThenList[i,j].Tot:
=List[i-1,j-1].Tot+List[i,j].Val;
{若从[i-1,j-1]选择右斜线向下会使[1,1]至[i,j]的数字和最大,则决策该步}
If(j<>i)And(List[i-1,j].Tot+List[i,j].Val>List[i,j].Tot)ThenList[i,j].Tot:
=List[i-1,j].Tot+List[i,j].Val
{若从[i-1,j]选择左斜线向下会使[1,1]至[i,j]的数字和最大,则决策该步}
End;{for}
Max:
=1;
{[1,1]至底行各点的N条路径所经过的数字和中,选择最大的一个输出}
Fori:
=2toNDo
IfList[N,i].Tot>List[N,Max].TotThen
Max:
=i;
Writeln(List[N,Max].Tot){输出最大总和}
End;{main}
Begin
Init;{读入数字三角形}
Main{求最大总和}
End.{main}
例2:
最长不下降序列(HNOI’97)
【问题描述】
设有整数序列b1,b2,b3,…,bm,若存在i1 求序列b1,b2,b3,…,bm中所有长度(n)最大不下降子序列 输入: 整数序列 输出: 最大长度n和所有长度为n的序列个数Total 【分析】 此题分为两个部分: 求最大不下降序列长度和序列个数。 首先我们考虑求最大长度。 设F(i)为前I个数中的最大不下降序列长度。 由题意不难得知,要求F(i),需要求得F (1)—F(I-1),然后选择一个最大的F(j)(jbj),那么前I个数中最大不下降序列便是前j个数中最大不下降序列后添加bi而得。 可见此任务满足最优子结构,可以用动态规划解决。 通过上面的分析可得状态转移方程如下: F(i)=max{F(j)+1}(j 边界为F (1)=1 显然只需要求序列个数即可。 很容易想到下面的方法: 设Total(I)为前I个数中最长不下降序列的个数。 那么,要求Total(i),只需找到所有的Total(j)满足j 即 Total(i)=∑Total(j)(j 在求所有的Total(i)(F(i)=max)的累加和即可。 但这样考虑有一个致命的错误,如 122 这样一个序列,最大不下降序列长度为2。 但如果按上述方法计算序列12会算两次。 因此,我们对算法进行改进: 对原序列按b从小到大(当bi=bj时按F从大到小)排序,增设Order(i)记录新序列中的I个数在原序列中的位置。 可见,当求Total(i)时,当F(j)=F(j+1),b(j)=b(j+1)且Order(j+1) 这样就避免了重复。 综合看来,上述算法的时间复杂度为O(n^2),空间复杂度为O(n),都是可行的。 【参考程序】 {$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S-,T-,V+,X+} {$M65520,0,655360} ProgramHNOI97_1; constfinp='input.txt'; fout='output.txt'; maxN=1000; varn,len: integer;{len记录最大长度} tot: longint;{tot记录序列个数} f,b: array[1..maxN]ofinteger; Procedureinit;{输入} varf: text; begin assign(f,finp);reset(f); n: =0; whilenoteoln(f)dobegin inc(n); read(f,b[n]) end; close(f) end; Proceduremain; vari,j,t: integer; order: array[1..maxN]ofinteger; total: array[1..maxN]oflongint; begin f[1]: =1;len: =1;{求解最大不下降序列长度} fori: =2tondobegin f[i]: =1; forj: =1toi-1do if(b[i]>b[j])and(f[i] f[i]: =f[j]+1; iff[i]>lenthenlen: =f[i]{记录最大值} end; fori: =1tondoorder[i]: =i; fori: =1tondo{排序} forj: =i+1tondo if(b[i]>b[j])or(b[i]=b[j])and(f[i]>f[j])thenbegin t: =b[i];b[i]: =b[j];b[j]: =t; t: =f[i];f[i]: =f[j];f[j]: =t; t: =order[i];order[i]: =order[j];order[j]: =t end; tot: =0;{计算序列个数} fillchar(total,sizeof(total),0); fori: =1tondobegin iff[i]=1thentotal[i]: =1 else forj: =i-1downto1do if(f[j]=f[i]-1)and(b[j] if(b[j+1]<>b[j])or(f[j+1]<>f[j])or(order[j+1]>=order[i])then inc(total[i],total[j]); if(f[i]=len)and(b[i]<>b[i+1])then{记录累加最终值} tot: =tot+total[i] end; end; Procedureout;{输出} begin assign(output,fout);rewrite(output); writeln(len); writeln(tot); close(output) end; Begin init; main; out End. 例3: BUYLOW,BUYLOWER 【问题描述】“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。 要想被认为是伟大的投资者,你必须遵循以下的问题建议: “低价购买;再低价购买”。 每次你购买一支股票,你必须用低于你上次购买它的价格购买它。 买的次数越多越好! 你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。 你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票。 每次购买都必须遵循“低价购买;再低价购买”的原则。 写一个程序计算最大购买次数。 这里是某支股票的价格清单: 日期123456789101112 价格686954646864706778629887 最优秀的投资者可以购买最多4次股票,可行方案中的一种是: 日期25610 价格69686462 【问题输入】 第1行: N(1<=N<=5000),股票发行天数 第2行: N个数,是每天的股票价格。 【问题输出】输出文件仅一行包含两个数: 最大购买次数和拥有最大购买次数的方案数(<=231)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这2种方案被认为是相同的。 【输入样例】BUYLOW.IN 12 686954646864706778629887 【输出样例】BUYLOW.OUT 42 【问题分析】问题的第一部分是要求输入数据串中的一个最长下降序列的长度,可使用动态规划的方法,具体做法是从序列的最后一个元素开始,依次求出以第i个元素为第一个元素时的最长下降序列的长度len[i],显然len[n]=1,len[i]=max(len[j]+1),其中i 序列中第j个元素小于第i个元素。 所有的len[i]中最大的一个即为输入数据中最长下降序列的长度,将它记为maxlen。 第二部分比较有难度。 由于它紧接着第一问,所以一般说来应该充分利用第一个问题的结论,对于任意一个最长下降序列,设它的第一个元素的下标为i1,第二个元素的下标为i2,其余元素的下标以些类推,则显然有len[i1]=maxlen,len[i2]=maxlen-1……,现在要求所有不同的最长下降序列的总数,则只要按照数组len的值从小到大对整个序列从后向前递推即可,以序列a=(5,3,1,4,2)为例,len[1]=3,len[2]=2,len[3]=1,len[4]=2,len[5]=1,用t[i]记录以第i个元素为头一个元素到序列结束为止的最长下降序列的不同方案总数,若len[i]=1,则t[i]=1,本例中由len[3]=1,len[5]=1可知t[3]=1,t[5]=1,再由len[5]=1,len[4]=2且a[4]=4>a[5]=2可得t[4]=1,由len[5]=1,len[2]=2且a[2]=3>a[5]=2和len[3]=1,len[2]=2且a[2]=3>a[3]=1可得t[2]=t[5]+t[3]=2,对应{a[2],a[3]}和{a[2],a[5]}两个不同的以a2起头的最长下降序列,最终由len[4]=2,len[1]=3且a[1]=5>a[4]=4和len[2]=2,len[1]=3且a[1]=5>a[2]=3可得t[1]=t[4]+t[2]=1+2=3,所以本例中最长下降序列总数为3,分别为{5,4,2},{5,3,2}和{5,3,1}。 对于有相同元素的序列来说,如序列a=(5,4,1,4,2),其中有两个相同的元素4,前面的推导过程不变,最后一步推导受两个相同元素的影响,不能能简单相加,由于a2=a4=4,对于所有的以a4起头的最长下降序列,只要将a4改为a2即可得到同样长度的下降序列,所以t[4]中的统计的序列在t[2]中也统计在内了,当序列中有相同元素时,为避免重复计数,从后向前递推时当后面的元素遇到前面的相同元素时则不再向前推。 程序中为了方便处理,在整个序列前设置了一个标致元素a[0]=maxlongint,将len[0]置为maxlen+1。 【参考程序】 Programp8_3(Input,Output); constmaxn=5000; vari,j,n,l,maxlen: longint; a,len,t: array[0..maxn]oflongint; begin assign(input,'buylow.in'); reset(input); assign(output,'buylow.out'); rewrite(output); readln(n); fori: =1tondoread(a[i]); fori: =1tondolen[i]: =1; fori: =n-1downto1do forj: =i+1tondo if(a[j]=len[i])thenlen[i]: =len[j]+1; maxlen: =1; fori: =1tondoiflen[i]>maxlenthenmaxlen: =len[i]; a[0]: =maxlongint;len[0]: =maxlen+1; fori: =0tondoiflen[i]=1thent[i]: =1elset[i]: =0; forl: =1tomaxlendo begin fori: =ndownto1do iflen[i]=lthen begin j: =i-1; while(j>=0)and(a[j]<>a[i])do begin if(a[j]>a[i])and(len[j]=l+1)theninc(t[j],t[i]); dec(j) end; end; end; writeln(maxlen,'',t[0]); close(input); close(output); end. 例4: 01背包问题 【问题描述】: 有N件物品和一个容量为V的背包。 第i件物品的费用是c[i],价值是w[i]。 求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 基本思路: 这是最基础的背包问题,特点是: 每种物品仅有一件,可以选择放或不放。 用子问题定义状态: 即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。 则其状态转移方程便是: f[i][v]=max{f
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 动态 规划 学习 资料