动态规划入门2Word格式.docx
《动态规划入门2Word格式.docx》由会员分享,可在线阅读,更多相关《动态规划入门2Word格式.docx(25页珍藏版)》请在冰豆网上搜索。
![动态规划入门2Word格式.docx](https://file1.bdocx.com/fileroot1/2022-12/29/693995e7-4977-4e4f-9779-8499a9f1e78b/693995e7-4977-4e4f-9779-8499a9f1e78b1.gif)
ifi=n-1then{到达三角阵底行}
ifmax<
sthenmax:
=s;
{保存最大值}
solve(u,v);
{试走下一步}
=s-a[u,v];
{恢复累加和}
end;
end;
BEGIN{主程序}
init;
{初始化数组a}
max:
s:
=a[1,1];
c[1]:
=1;
d[1]:
{K=1时坐标增量}c[2]:
d[2]:
{K=2时坐标增量}solve(1,1);
writeln(max);
END.
上述“回溯算法”的效率太低,因为每回溯一步然后再下发展时,有很多步都是重复的计算,浪费了太多的时间。
经测试当行数N>
25时,运行时间太长难以承受,原题中行数N的上限是100,因此必须另找更好的算法。
3.下面我们来进行深入的分析,假如已经走第I行第J列,此时最大累加和S[I,J]应选S[I-1,J-1],S[I-1,J]中较大者再加上(I,J)处的值A[I,J],即下式
S[I,J]=A[I,J]+MAX(S[I-1,J-1],S[I-1,J])
所以我们可以从第一行开始,向下逐行推出每一处位置的最大累加和S,最后从底行的N个S中选出最大的一个即为所求。
Functionmax1(i,j:
longint):
longint;
{求两数中较大
Begin的一个}
ifi>
jthenmax1:
=ielsemax1:
=j;
Proceduresolve;
{递推求b[i.j]}
vari,j,max:
begin
fori:
=1tondo
forj:
=1toido
b[i,j]:
=max1(b[i-1,j],b[i-1,j-1])+a[i,j];
ifb[i,j]>
maxthenmax:
=b[i,j];
{初始化}
solve;
经测试N=100时,速度仍相当快完全符合要求。
从上分析可以看出,此题难度随行数N的增加而加大。
当N<
10时,可以作为初学者或小学生的试题;
当10<
N<
25时可以作为初中生试题;
当N>
25时作为高中试题。
通过以上对程序算法的不断优化,使编程水平一次又一次得到提高。
从简单的循环嵌套到“回溯”直到“动态规划”思想的应用。
2.动态规划的理论基础
通过上面的例子,我们对“动态规划”有了一个初步认识,它所处理的问题是一个“多阶段决策问题”。
我们现在对一些概念进行具体定义:
状态(State):
它表示事物的性质,是描述“动态规划”中的“单元”的量。
如例1中的每个节点(指节点处的最大值)都为单个的状态。
阶段(Stage):
阶段是一些性质相近,可以同时处理的状态集合。
通常,一个问题可以由处理的先后次序划分为几个阶段。
如例1中的问题,每一行若干节点组成一个阶段。
一个阶段既可以包含多个状态,也可以只包含一个状态。
描述各阶段状态的变量称为状态变量,例1中可用S[4,j]来表示第四阶段(即第四行)走到第j列的最大值,即第四阶段状态变量。
状态转移方程:
是前一个阶段的状态转移到后一个的状态的演变规律,是关于两个相邻阶段状态的方程,是“动态规划”的中心。
如例1中:
S[I,J]=A[I,J]+MAX(S[I-1,J],S[I-1,J+1])
决策(Decision):
每个阶段做出的某种选择性的行动。
它是我们程序所需要完成的选择。
如例1中MAX(S[I-1,J],S[I-1,J+1])
动态规划所处理的问题是一个“多阶段决策问题”,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。
这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。
如图3所示。
总体上来说,一个“动态规划”算法应该包含上面提到的几种基本关系与属性。
那么,什么样的“决策问题”才可以划分阶段,来用“动态规划”求解呢?
我们说一个“决策问题”只有具有以下性质时,才可以考虑划分阶段,用“动态规划”算法:
一:
最优子结构
即一个问题的最优解只取决于其子问题的最优解,也就是说,非最优解对问题的求解没有影响。
我们再来看一个问题:
〖例2〗有4个点,分别是A、B、C、D,如图4所示,相邻两点用两条连线C2k,C2k-1(1≤k≤3)表示两条通行的道路。
连线上方的数字表示道路的长度。
我们定义从A到D的所有路径中,长度除以4所得余数最小的路径为最优路径。
求一条最优路径。
在这个题目中,我们如果还按照刚才的方法来求解就会发生错误。
例如,按照例1的思维,C最优取值可以由B的最优取值来确定,而B的最优取值为2,所以C的最优值为3(C1+C3),而实际上,路径C2—C3可得最优值为0,所以,C的最优路径并不是B最优路径的子路径,也就是说,C的最优取值不是由B的最优取值决定的,其不具有最优子结构。
由此可见,并不是所有的“决策问题”都可以用“动态规划”来解决。
所以,只有当一个问题呈现出最优子结构时,“动态规划”才可能是一个合适的侯选方法。
二:
无后效性
即一个问题被划分阶段后,阶段I中的状态只能由阶段I-1中的状态通过状态转移方程得来,与其他状态没有关系,特别是与未发生的状态没有关系,这就是无后效性。
3.典型例题分析
3-1求最长不下降序列
一.问题描述
设有由n个不相同的整数组成的数列,记为:
a
(1)、a
(2)、……、a(n)且a(i)<
>
a(j)(i<
j)
例如3,18,7,14,10,12,23,41,16,24。
若存在i1<
i2<
i3<
…<
ie且有a(i1)<
a(i2)<
…
<
a(ie)则称为长度为e的不下降序列。
如上例中3,18,23,24就是一个长度为4的不下降序列,同时也有3,7,10,12,16,24长度为6的不下降序列。
程序要求,当原数列给出之后,求出最长的不下降序列。
二.算法分析
(一)。
根据动态规划的原理,由后往前进行搜索。
1·
对a(n)来说,由于它是最后一个数,所以当从a(n)开始查找时,只存在长度为1的不下降序列;
2·
若从a(n-1)开始查找,则存在下面的两种可能性:
①若a(n-1)<
a(n)则存在长度为2的不下降序列a(n-1),a(n)。
②若a(n-1)>
a(n)则存在长度为1的不下降序列a(n-1)或a(n)。
3·
一般若从a(i)开始,此时最长不下降序列应该按下列方法求出:
在a(i+1),a(i+2),…,a(n)中,找出一个比a(i)大的且最长的不下降序列,作为它的后继。
倒推公式为
F(I)=MAX{F(I+K)}+1
F[I]:
表示以第I个位置为起点的最长不下降序列的长度。
K的选择范围:
a(I+k)>
a(i)I+k≦n
最后从F[1]到F[N]中选取最大的即为最优解
当然也可以采用顺推的方法,顺推公式为
F(I)=MAX{F(I-K)}+1
表示以第I个位置为终点的最长不下降序列的长度。
a(I-k)<
a(i)I-k≧1
最后从F[1]到F[N]中选取最大的即为最优解
4·
为算法上的需要,定义一个数组(倒推法)
整数类型二维数组d(N,3)
d(I,1)表示点a(i)
d(I,2)表示从I位置到达N的最长不下降序列长度
d(I,3)表示从I位置开始最长不下降序列的下一个数字的位置,以便打印。
初始化:
FORI=1TON
INPUT#1,D(I,1)
D(I,2)=1
D(I,3)=0
NEXTI
下面给出求最长不下降序列的算法:
FORI=N-1TO1STEP-1
L=0:
P=0
FORJ=I+1TON
IFD(I,1)<
D(J,1)ANDD(J,2)>
LTHEN
L=D(J,2)
P=J
ENDIF
NEXTJ
IFL>
0THEN
D(I,2)=L+1
D(I,3)=P
下面找出最长不下降序列:
DMAX=D(1,2)
L=1
FORI=2TON-1
IFD(I,2)>
DMAXTHEN
DMAX=D(I,2)
L=I{记录最长不下降序列的起点位置}
最长不下降序列长度为D(L,2)
序列
WHILEL<
0
PRINTD(L,1);
L=D(L,3)
WEND
(3)程序清单
PROGRAMMAX_RISE(INPUT,OUTPUT);
CONSTMAXN=100;
FNAME='
Q21.TXT'
;
TYPETLIST=ARRAY[1..MAXN,1..3]OFINTEGER;
VARD:
TLIST;
N:
BYTE;
PROCEDUREINIT;
VAR
I:
INTEGER;
F:
TEXT;
BEGIN
ASSIGN(F,FNAME);
RESET(F);
READLN(F,N);
FORI:
=1TONDO
READ(F,D[I,1]);
D[I,2]:
D[I,3]:
=0
END;
CLOSE(F);
PROCEDUREMAKE;
I,J,P:
L:
=N-1DOWNTO1DO
P:
FORJ:
=I+1TONDO
IF(D[I,1]<
D[J,1])AND(D[J,2]>
L)THEN
=D[J,2];
=J;
IFL>
0THEN
=L+1;
=P;
PROCEDUREOUTPUT;
I,L,DMAX:
WRITE('
SOURCE:
'
);
=1TONDOWRITE(D[I,1]:
5);
WRITELN;
DMAX:
=D[1,2];
=2TON-1DO
IFD[I,2]>
DMAXTHEN
=D[I,2];
=I;
RESULTIS:
'
WHILEL<
0DO
WRITE(D[L,1]:
=D[L,3];
WRITELN('
MAXLENGTH='
D[DMAX,2]);
INIT;
MAKE;
OUTPUT;
INPUT:
10
318714101223411624
OUTPUT:
318714101223411624
3710122341
MAXLENGTH=6
三:
应用举例
1、防卫导弹:
问题描述:
一种新型的防卫导弹可截击多个攻击导弹。
它可以向前飞行,也可以用很快的速度向下飞行,可以毫无损伤地截击进攻导弹,但不可以向后或向上飞行。
但有一个缺点,尽管它发射时可以达到任意高度,但它只能截击比它上次截击导弹时所处高度低或者高度相同的导弹。
现对这种新型
防卫导弹进行测试,在每一次测试中,发射一系列的测试导弹(这些导弹发射的间隔时间固定,飞行速度相同),该防卫导弹所能获得的信息包括各进攻导弹的高度,以及它们发射次序。
现要求编一程序,求在每次测试中,该防卫导弹最多能截击的进攻导弹数量,一个导弹能被截击应满足下列两个条件之一:
1、它是该次测试中第一个被防卫导弹截击的导弹;
2、它是在上一次被截击导弹的发射后发射,且高度不大于上一次被截击导弹的高度的导弹。
输入格式:
从当前目录下的文本文件"
CATCHER.DAT"
读入数据。
该文件的第一行是一个整数N(0〈=N〈=4000),表示本次测试中,发射的进攻导弹数,以下N行每行各有一个整数hi(0〈=hi〈=32767),表示第i个进攻导弹的高度。
文件中各行的行首、行末无多余空格,
输入文件中给出的导弹是按发射顺序排列的。
输出格式:
答案输出到当前目录下的文本文件"
CATCHER.OUT"
中,该文件第一行是一个整数max,表示最多能截击的进攻导弹数,以下的max行每行各有一个整数,表示各个被截击的进攻导弹的编号(按被截击的先后顺序排列)。
输出的答案可能不唯一,只要输出其中任一解即可。
输入输出举例:
输入文件:
CATCHER.DAT
3
25
36
23输出文件:
CATCHER.OUT
2
1
算法分析:
求最长不递增序列。
2、轮船(Ships)
描述
有一个国家被一条何划分为南北两部分,在南岸和北岸总共有N个城镇,每一城镇在对岸都有唯一的友好城镇。
任何两个城镇都没有相同的友好城镇。
每一对友好城镇都希望有一条航线来往。
于是他们向政府提出了申请。
由于河终年有雾。
政府决定不允许有任两条航线交叉(如果两条航线交叉,将有很大机撞船)。
你的任务是缟写一个程序来帮政府官员决定他们应拨款兴建哪些航线以使到没有出现交叉的航线最多。
输入数据
输入文件(ship.in)包括了若干组数据,每组数据格式如下:
第一行两个由空格分隔的整数x,y,10〈=x〈=6000,10〈=y〈=100。
x
表示河的长度而y表示宽。
第二行是一个整数N(1<
=N<
=5000),表示分布在河两岸的城镇对数。
接下来的N行每行有两个由空格分隔的正数C,D(C、D〈=x〉,描述每一对友好城镇沿着河岸与西边境线的距离,C表示北岸城镇的距离而D表示南岸城镇的距离。
在河的同一边,任何两个城镇的位置都是不同的。
整个输入文件以由空格分隔的两个0结束。
输出数据
输出文件(ship.ou)要在连续的若干行里给出每一组数据在安全条件下能够开通的最大航线数目。
示例
Ship.in
304
224
26
103
1512
98
1717
42
00
Ship.out
4
算法分析。
我们将航线按起点坐标排好序后,只要线J的起点小于线I的起点,同时它的终点也小于线I的终点,则线J和线I不相交。
因此,求所有线中最多能有多少条线不相交,实际上是从终点坐标值数列中求一个最长不下降序列。
这就把题目转化为一个非常典型的动态规划题目了。
求最长不下降序列的规划方程如下:
L(Si)=max{L(Sj)}+1;
1<
=j<
i且Sj<
Si。
Si为航线的终点坐标值。
3-2挖地雷
一.问题描述
在一条公路上埋有若干堆地雷,每堆地雷有一定的数量,地雷堆的编号为1,2,…,N,例如,埋有地雷数量如下:
8
14
2
17
33
26
15
196
此时,地雷的数量可用一维数组A(N)表示。
同时,给出地雷堆之间的联系,从第1堆开始,它指出挖了此堆之后,还可以选择继续往下挖,若存在多种方案,只能选择其中的一种,若没有任何后继的方案,则挖地雷结束。
例如,可给出下面的关系:
从上图可看出,若从第1堆开始挖,首先得到8枚地雷,然后,下面有2种选择3、4,若选择3,则可挖到2枚,下面还可以继续挖,或选择4此时可挖到17枚,到此结束,总共可挖到8+17=25枚。
或选择1--3--6--7--8--10此时可挖到74枚。
但也可以从2开始挖,后选择2--3--6--7--8--10,则共可挖到14+26+15+17+6=80枚,但还不是最多的,最多的为5--6--7--8--10,此时共可挖到33+26+15+17+6=97枚。
地雷堆之间的联系可用以下的数组表示:
二维整数型数组R(I,J)表示,当R(I,J)=1表示从I到J有通路,当R(I,J)=0表示无通路。
上例中的R如下图
二:
算法:
“动态规划”----采用倒推的方法
1·
由后往前查找:
若从第n堆地雷开始挖,此时可能得到a(n)枚地雷。
若从第n-1堆地雷开始挖,此时有2种可能:
①n-1堆到n堆无联系(可由R(n-1,n)判断),此时可挖a(n-1)枚。
②n-1堆到n堆有联系,则可挖a(n-1)+a(n)枚。
一般情况,若从第i堆开始挖,根据关系R,找出i后面的所有联系,从中找出一个可挖最多地雷的作为联系,这样可得到最多的挖地雷数。
2·
上面计算出从每个堆开始能挖到最多的地雷数,此时找出一个最大值即可。
3.递推公式
设:
F[I]从第I个节点出发的最大挖雷数
A[I]第I个节点处的地雷数目
倒推公式为:
F[I]=MAX{F[I+K]}+A[I]
R[I,I+K]=1即节点I与I+K之间有通路且I+K≦N
初始条件:
F[N]=A[N]
最后从F[1]至F[N]中选取最大的即为所求。
4·
算法流程。
①定义数据结构,整数型二维数组B(N,2)
B(i,1)表示以I为起点最多可挖地雷数。
B(i,2)向后连接,表示下一个节点的位置,以便打印。
②求从第i堆地雷开始挖的数量的算法:
CMAX=0:
H=0
FORJ=I+1TON
IFR(I,J)=1ANDB(J,1)>
CMAXTHEN
H=J:
CMAX=B(J,1)
NEXTJ
B(I,1)=A(I)+CMAX
B(I,2)=H
③找出最大值并找出挖的路径:
FORI=1TON
IFB(I,1)>
H=I{记录起点位置}
CMAX=B(I,1)
NEXTI
PRINT"
最大可挖数量:
"
CMAX
PRINTH
WHILEB(H,2)<
0
H=B(H,2)
PRINT"
->
H;
5.源程序
PROGRAMGROUND_BOMB(INPUT,OUTPUT);
CONSTmax=100;
Fname='
Q71.txt'
TYPE
TLEI=ARRAY[1..MAX]OFINTEGER;
TNET=ARRAY[1..MAX,1..MAX]OF0..1;
TWAY=ARRAY[0..MAX,1..2]OFINTEGER;
A:
TLEI;
R:
TNET;
B:
TWAY;
i,j:
FILLCHAR(A,SIZEOF(A),0);
FILLCHAR(R,SIZEOF(R),0);
FILLCHAR(B,SIZEOF(B),0);
FORi:
=1TOnDO
READ(F,A[I]);
FORI:
=1TONDO
FORJ:
=ITONDO
READ(F,R[i,j]);
PROCEDUREWORK;
i,j,H:
BYTE;
CMAX:
INTEGER;
=NDOWNTO1DO
=0;
H:
IF(R[I,J]=1)AND(B[J,1]>
CMAX)THEN
H:
CMAX:
=B[j,1];
B[I,1]:
=A[I]+CMAX;
B[I,2]:
=H;
IFB[I,1]>
=B[i,1];
MAXGET:
CMAX);
IFH<
0THENWRITE(H);
WHILEB[H,2]<
=B[H,2];
-->
H);
WORK;
6
814217926
001100
01000
0101
000
01
MAXGET:
42
2---->
3---->
6
三.顺推法
顺推公式为:
F[I]=MAX{F[I-K]}+A[I]
注意:
F[I]以第I个节点为终点的最大挖雷数
R[I,I-K]=1即节点I与I-K之间有通路且I-K≥1
F[1]=A[1]
最后从F[1]至F[N]中选取最大的即为所求
3-3一组动态规划题
一.最小代价字母数
源程序:
dai_jia.pas
二.石子和并(95’NOI试题)
在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆。
规