高中计算机竞赛编程动态规划解析辅导文档格式.docx
- 文档编号:16815723
- 上传时间:2022-11-26
- 格式:DOCX
- 页数:54
- 大小:370.88KB
高中计算机竞赛编程动态规划解析辅导文档格式.docx
《高中计算机竞赛编程动态规划解析辅导文档格式.docx》由会员分享,可在线阅读,更多相关《高中计算机竞赛编程动态规划解析辅导文档格式.docx(54页珍藏版)》请在冰豆网上搜索。
K=1有
F1(A)=MIN{D1(A,B1)+F2(B1),D1(A,B2)+F2(B2)}
=MIN{5+9,3+10}=13。
因此由A点到E点的全过程最短路径为A→B2→C4→D3→E;
最短路程长度为13。
从以上过程可以看出,每个阶段中,都求出本阶段的各个初始状态到终点E的最短距离,当逆序倒推到过程起点A时,便得到了全过程的最短路径和最短距离。
在上例的多阶段决策问题中,各个阶段采取的决策,一般来说是与阶段有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,我们称这种解决多阶段决策最优化的过程为动态规划程序设计方法。
(二)动态规划的基本概念和基本模型构成
现在我们来介绍动态规划的基本概念。
1.阶段和阶段变量:
用动态规划求解一个问题时,需要将问题的全过程恰当地分成若干个相互联系的阶段,以便按一定的次序去求解。
描述阶段的变量称为阶段变量,通常用K表示,阶段的划分一般是根据时间和空间的自然特征来划分,同时阶段的划分要便于把问题转化成多阶段决策过程,如例题3-1-1中,可将其划分成4个阶段,即K=1,2,3,4。
2.状态和状态变量:
某一阶段的出发位置称为状态,通常一个阶段包含若干状态。
一般地,状态可由变量来描述,用来描述状态的变量称为状态变量。
如例题3-1-1中,C3是一个状态变量。
3.决策、决策变量和决策允许集合:
在对问题的处理中作出的每种选择性的行动就是决策。
即从该阶段的每一个状态出发,通过一次选择性的行动转移至下一阶段的相应状态。
一个实际问题可能要有多次决策和多个决策点,在每一个阶段的每一个状态中都需要有一次决策,决策也可以用变量来描述,称这种变量为决策变量。
在实际问题中,决策变量的取值往往限制在某一个范围之内,此范围称为允许决策集合。
如例题3-1-1中,F3(C3)就是一个决策变量。
4.策略和最优策略:
所有阶段依次排列构成问题的全过程。
全过程中各阶段决策变量所组成的有序总体称为策略。
在实际问题中,从决策允许集合中找出最优效果的策略成为最优策略。
5.状态转移方程
前一阶段的终点就是后一阶段的起点,对前一阶段的状态作出某种决策,产生后一阶段的状态,这种关系描述了由k阶段到k+1阶段状态的演变规律,称为状态转移方程。
在上面介绍的动态规划基本概念的基础上,可以得到动态规划的基本模型构成如下:
1.确定问题的决策对象。
2.对决策过程划分阶段。
3.对各阶段确定状态变量。
4.根据状态变量确定费用函数和目标函数。
5.建立各阶段状态变量的转移过程,确定状态转移方程。
(三)最优化原理与无后效性
上面已经介绍了动态规划模型的基本组成,现在需要解决的问题是:
什么样的“多阶段决策问题”才可以采用动态规划的方法求解。
一般来说,能够采用动态规划方法求解的问题,必须满足最优化原理和无后效性原则:
1.动态规划的最优化原理。
作为整个过程的最优策略具有:
无论过去的状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略的性质。
也可以通俗地理解为子问题的局部最优将导致整个问题的全局最优,即问题具有最优子结构的性质,也就是说一个问题的最优解只取决于其子问题的最优解,而非最优解对问题的求解没有影响。
在例题3-1-1最短路径问题中,A到E的最优路径上的任一点到终点E的路径,也必然是该点到终点E的一条最优路径,即整体优化可以分解为若干个局部优化。
2.动态规划的无后效性原则。
所谓无后效性原则,指的是这样一种性质:
某阶段的状态一旦确定,则此后过程的演变不再受此前各状态及决策的影响。
也就是说,“未来与过去无关”,当前的状态是此前历史的一个完整的总结,此前的历史只能通过当前的状态去影响过程未来的演变。
在例题3-1-1最短路径问题中,问题被划分成各个阶段之后,阶段K中的状态只能由阶段K+1中的状态通过状态转移方程得来,与其它状态没有关系,特别与未发生的状态没有关系,例如从Ci到E的最短路径,只与Ci的位置有关,它是由Di中的状态通过状态转移方程得来,与E状态,特别是A到Ci的路径选择无关,这就是无后效性。
由此可见,对于不能划分阶段的问题,不能运用动态规划来解;
对于能划分阶段,但不符合最优化原理的,也不能用动态规划来解;
既能划分阶段,又符合最优化原理的,但不具备无后效性原则,还是不能用动态规划来解;
误用动态规划程序设计方法求解会导致错误的结果。
二、动态规划的设计与实现
(一)动态规划设计方法的一般模式
动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态;
或倒过来,从结束状态开始,通过对中间阶段决策的选择,达到初始状态。
这些决策形成一个决策序列,同时确定了完成整个过程的一条活动路线,通常是求最优活动路线。
动态规划的设计都有着一定的模式,一般要经历以下几个步骤:
1.划分阶段:
按照问题的时间或空间特征,把问题划分为若干个阶段。
在划分阶段时,注意划分后的阶段一定是有序的或者是可排序的,否则问题就无法求解。
2.确定状态和状态变量:
将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。
当然,状态的选择要满足无后效性。
3.确定决策并写出状态转移方程:
因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。
所以如果确定了决策,状态转移方程也就可以写出。
但事实上常常是反过来做,根据相邻两段的各个状态之间的关系来确定决策。
4.寻找边界条件:
给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
5.程序的设计实现:
一旦设计完成,实现就会非常简单。
下面我们给出从初始状态开始,通过对中间阶段决策的选择,达到结束状态,按照阶段、状态和决策的层次关系,写出的程序流程的一般形式:
所有状态费用的初始化;
fori:
=阶段最大值-1downto1do{倒推每一个阶段}
forj:
=状态最小值to状态最大值do{枚举阶段i的每一个状态}
fork:
=决策最小值to决策最大值do{枚举阶段i中状态j可选择的每一种决策}
begin
f[i,j]←min{d[i,j,k]+f[i+1,k]}
end;
输出f[1,1];
例3-2-1对应的Pascal程序如下:
var
d:
array[1..4,1..4,1..4]ofbyte;
f:
array[1..5,1..4]ofbyte;
i,j,k,min:
byte;
begin
fillchar(d,sizeof(d),0);
d[1,1,1]:
=5;
d[1,1,2]:
=3;
d[2,1,1]:
=1;
d[2,1,2]:
=6;
d[2,1,3]:
d[2,2,2]:
=8;
d[2,2,4]:
=4;
d[3,1,1]:
d[3,1,2]:
d[3,2,1]:
d[3,3,3]:
d[3,4,3]:
d[4,1,1]:
d[4,2,1]:
d[4,3,1]:
fillchar(f,sizeof(f),255);
f[5,1]:
=0;
fori:
=4downto1do
forj:
=1to4do
fork:
ifd[i,j,k]<
>
0then
iff[i,j]>
d[i,j,k]+f[i+1,k]thenf[i,j]:
=d[i,j,k]+f[i+1,k];
writeln(f[1,1]);
readln;
end.
(二)动态规划方法实现的灵活性与技巧性
这里需要说明的是,上述程序流程仅是提供了解题的一种思路或方法,并不是说所有解题的程序流程都应如此。
例如:
●若每一个阶段仅一个出发位置,则可通过一重循环枚举各个阶段的状态;
●若状态非一个整数值所能描述(例如代表平面或空间上的一个坐标),则枚举状态的第二重循环可由相应的多重循环替代;
●如果可供选择的决策较少或者较难定义决策序号,则取消枚举决策的第三重循环,将决策过程直接放入状态转移方程或者在循环体内编写决策选择程序;
我们必须从问题本身和解题需求出发,具体问题具体分析,制定行之有效的策略。
特别是作为信息学竞赛中的动态规划问题,考察的知识面是多方面的,应用的技巧也是多变的。
例3-2-2:
拦截导弹。
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种拦截系统有一个缺陷:
虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭,由于该系统还在试用阶段。
所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度不大于30000的正整数)。
计算这套系统最多能拦截多少导弹。
输入:
依次飞来的导弹高度(1≤N≤1000)。
输出:
一套系统最多拦截的导弹数,并依次打印输出被拦截导弹的高度。
在本题中不仅要求输出最优解,而且还要求输出最优解的形成过程。
为此,我们设置了一张记忆表C[i],在按从后往前方式求解的过程中,将每一个子问题的最佳决策保存起来,避免在输出方案时重复计算。
阶段i:
由右而左计算导弹n‥导弹1中可拦截的最多导弹数(1≤i≤n);
状态B[i]:
由于每个阶段中仅一个状态,因此可通过一重循环
=n-1downto1do枚举每个阶段的状态B[i];
决策k:
在拦截导弹i之后应拦截哪一枚导弹可使得B[i]最大(i+1≤k≤n),
a,b,c:
array[1..1000]ofword;
n,i,j,k,max:
word;
writeln('
INPUT:
'
);
{初始化,读入数据}
n:
whilenoteolndobegin
inc(n);
read(a[n]);
b[n]:
c[n]:
end;
=n-1downto1dobegin{枚举每一个阶段的状态,设导弹i被拦截}
max:
j:
=i+1tondo{枚举决策,计算最佳方案中拦截的下一枚导弹}
if(a[k]<
=a[i])and(b[k]>
max)thenbegin
=b[k];
=k;
b[i]:
=max+1;
c[i]:
=j;
{若导弹i之后拦截导弹j为最佳方案,则记下}
=1tondo{枚举求出一套系统能拦截的最多导数}
ifb[i]>
maxthenbeginmax:
=b[i];
=i;
OUTPUT'
{打印输出结果}
Max='
b[j]);
whilej>
0dobegin
write(a[j]:
5);
=c[j];
上面的两道例题都是倒推的,决策的选择也较多。
下面我们来讲一题是正推的,而且决策的选择较少。
例3-2-3:
数塔问题。
设有一个三角形的数塔,如下图所示。
顶点结点称为根结点,每个结点有一个整数数值,其值不超过100。
从顶点出发,可以向左走,也可以向右走。
从根13出发,向左走到达11,再向右走到达7,再向左走到达14,再向左到达7。
由于7是最底层,无路可走。
此时,我们找到一条从根结点开始到达底层的路径:
13-11-7-14-7。
路径上结点中数字的和,称为路径的值,如上面路径的值为13+11+7+14+7=52。
当三角形数塔给出之后,找出一条路径,使路径上的值为最大,打印输出最大路径的值。
数塔的层数N最多可为100。
算法分析:
此题贪心法往往得不到最优解,例如13-11-12-14-13其路径的值为63,但这不是最优解。
穷举搜索往往是不可能的,当层数N=100时,路径条数P=299这是一个非常大的数,即使用世界上最快的电子计算机,也不能在短时间内计算出来。
对这道题唯一正确的方法是动态规划。
如果得到一条由顶到底的某处的一条最佳路径,那么对于该路径上的每一个中间点来说,由顶至该中间点的路径所经过的数字和也为最大。
因此本题是一个典型的多阶段决策最优化问题。
在本题中仅要求输出最优解,为此我们设置了数组A[i,j]保存三角形数塔,B[i,j]保存状态值,按从上往下方式进行求解。
阶段i:
以层数来划分阶段,由从上往下方式计算层数1‥层数N(1≤i≤n);
因此可通过第一重循环
=1tondobegin枚举每一阶段;
状态B[i,j]:
由于每个阶段中有多个状态,因此可通过第二重循环
=1toidobegin求出每个阶段的每个状态的最优解B[i,j];
决策:
每个状态最多由上一层的两个结点连接过来,因此不需要做循环。
a,b:
array[1..100,0..100]ofword;
i,j,n:
repeat
write('
N='
readln(n);
untilnin[1..100];
fillchar(a,sizeof(a),0);
b:
=a;
=1tondobegin
=1toidoread(a[i,j]);
b[1,1]:
=a[1,1];
=2tondo
=1toido
ifb[i-1,j-1]>
b[i-1,j]
thenb[i,j]:
=b[i-1,j-1]+a[i,j]
elseb[i,j]:
=b[i-1,j]+a[i,j];
=1tondo
ifb[n,i]>
maxthenmax:
=b[n,i];
max);
三、多姿多彩的动态规划
动态规划是一种重要的程序设计思想,具有广泛的应用价值,在信息学竞赛中经常出现。
使用动态规划思想来设计程序,对于不少问题的解决往往具有高时效。
动态规划之所以具有高时效,是因为它在将问题规模不断减小的同时,有效地把一系列的局部最优解记录下来,从而避免了反复解同一个子问题的现象。
因而对于能够使用动态规划思想来解决的问题,使用动态规划是比较明智的选择。
动态规划是一种很灵活的解题方法,对不同的问题,有各具特色的解题方法,而不存在一种不变的动态规划算法,因此动态规划是多姿多彩的。
在动态规划思想的程序设计中,要深刻理解动态规划的本质,同时要多实践,不但要多解题,还要学会从解题中探寻规律,总结技巧。
动态规划是用空间换时间的一种方法的抽象。
其关键是发现子问题和记录其结果。
然后利用这些结果减轻运算量。
比如01背包问题:
/*一个旅行者有一个最多能用M公斤的背包,现在有N件物品,
它们的重量分别是W1,W2,...,Wn,
它们的价值分别为P1,P2,...,Pn.
若每种物品只有一件求旅行者能获得最大总价值。
输入格式:
M,N
W1,P1
W2,P2
......
输出格式:
X
*/
因为背包最大容量M未知。
所以,我们的程序要从1到M一个一个的试。
比如,开始任选N件物品的一个。
看对应M的背包,能不能放进去,如果能放进去,并且还有多的空间,则,多出来的空间里能放N-1物品中的最大价值。
怎么能保证总选择是最大价值呢?
看下表。
测试数据:
10,3
3,4
4,5
5,6
c[i][j]数组保存了1,2,3号物品依次选择后的最大价值.
这个最大价值是怎么得来的呢?
从背包容量为0开始,1号物品先试,0,1,2,的容量都不能放.所以置0,背包容量为3则里面放4.这样,这一排背包容量为4,5,6,....10的时候,最佳方案都是放4.假如1号物品放入背包.则再看2号物品.当背包容量为3的时候,最佳方案还是上一排的最价方案c为4.而背包容量为5的时候,则最佳方案为自己的重量5.背包容量为7的时候,很显然是5加上一个值了。
加谁?
?
很显然是7-4=3的时候.上一排c3的最佳方案是4.所以。
总的最佳方案是5+4为9.这样.一排一排推下去。
最右下放的数据就是最大的价值了。
(注意第3排的背包容量为7的时候,最佳方案不是本身的6.而是上一排的9.说明这时候3号物品没有被选.选的是1,2号物品.所以得9.)
从以上最大价值的构造过程中可以看出。
f(n,m)=max{f(n-1,m),f(n-1,m-w[n])+P(n,m)}这就是书本上写的动态规划方程.这回清楚了吗?
下面是实际程序:
#include<
stdio.h>
intc[10][100];
/*对应每种情况的最大价值*/
intknapsack(intm,intn)
{
inti,j,w[10],p[10];
for(i=1;
i<
n+1;
i++)
scanf("
\n%d,%d"
&
w[i],&
p[i]);
for(i=0;
10;
for(j=0;
j<
100;
j++)
c[i][j]=0;
/*初始化数组*/
for(j=1;
m+1;
{
if(w[i]<
=j)/*如果当前物品的容量小于背包容量*/
if(p[i]+c[i-1][j-w[i]]>
c[i-1][j])
/*如果本物品的价值加上背包剩下的空间能放的物品的价值*/
/*大于上一次选择的最佳方案则更新c[i][j]*/
c[i][j]=p[i]+c[i-1][j-w[i]];
else
c[i][j]=c[i-1][j];
}
elsec[i][j]=c[i-1][j];
return(c[n][m]);
}
intmain()
intm,n;
inti,j;
%d,%d"
m,&
n);
printf("
Inputeachone:
\n"
%d"
knapsack(m,n));
/*下面是测试这个数组,可删除*/
for(i=0;
15;
%d"
c[i][j]);
if(j==14)printf("
system("
pause"
例3-2-4演讲大厅安排:
有一个演讲大厅需要我们管理,演讲者们事先定好了需要演讲的起始时间和中止时间。
我们想让演讲大厅得到最大可能的使用。
我们要接受一些预定而拒绝其他的预定,目标是使演讲者使用大厅的时间最长。
假设在某一时刻一个演讲结束,另一个演讲就可以立即开始。
问题求解:
1、从文本文件HALL.IN中读入演讲者的申请。
2、计算演讲大厅最大可能的使用时间。
3、
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 高中 计算机 竞赛 编程 动态 规划 解析 辅导
![提示](https://static.bdocx.com/images/bang_tan.gif)