热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

NOIP竞赛学习整理动态规划算法举例P1264

动态规划什么是动态规划?动态规划是解决多阶段决策最优化问题的一种思想方法。所谓“动态”,指的是在问题的多阶段决策中,按某一顺序

动态规划


什么是动态规划?

动态规划是解决多阶段决策最优化问题的一种思想方法。所谓“动态”,指的是在问题的多阶段决策中,按某一顺序,根据每一步所选决策的不同,将随即引起状态的转移,最终在变化的状态中产生一个决策序列。动态规划就是为了使产生的决策序列在符合某种条件下达到最优。


一、动态规划中的主要概念,名词术语

1 阶段:把问题分成几个相互联系的有顺序的几个环节,这些环节即称为阶段。
2 状态:某一阶段的出发位置称为状态。通常一个阶段包含若干状态。如图1中,阶段3就有三个状态结点4、5、6。
3 决策:从某阶段的一个状态演变到下一个阶段某状态的选择。
4策略:由开始到终点的全过程中,由每段决策组成的决策序列称为全过程策略,简称策略。
5 状态转移方程:前一阶段的终点就是后一阶段的起点,前一阶段的决策选择导出了后一阶段的状态,这种关系描述了由k阶段到k+1阶段状态的演变规律,称为状态转移方程。
6 目标函数与最优化概念:目标函数是衡量多阶段决策过程优劣的准则。最优化概念是在一定条件下找到一个途径,经过按题目具体性质所确定的运算以后,使全过程的总效益达到最优。


二、动态规划问题的数学描述

首先,例举一个典型的且很直观的多阶段决策问题:
[例] 下图表示城市之间的交通路网,线段上的数字表示费用,单向通行由
A->E。试用动态规划的最优化原理求出 A->E 的最省费用。

在这里插入图片描述

如图从 A 到 E 共分为 4 个阶段,即第一阶段从 A 到 B,第二阶段从 B 到 C,
第三阶段从 C 到 D,第四阶段从 D 到 E。除起点 A 和终点 E 外,其它各点既是上
一阶段的终点又是下一阶段的起点。例如从 A 到 B 的第一阶段中,A 为起点,终
点有 B1,B2,B3 三个,因而这时走的路线有三个选择,一是走到 B1,一是走到
B2,一是走到 B3。若选择 B2 的决策,B2 就是第一阶段在我们决策之下的结果,
它既是第一阶段路线的终点,又是第二阶段路线的始点。在第二阶段,再从 B2
点出发,对于 B2 点就有一个可供选择的终点集合(C1,C2,C3);若选择由 B2
走至 C2 为第二阶段的决策,则 C2 就是第二阶段的终点,同时又是第三阶段的始
点。同理递推下去,可看到各个阶段的决策不同,线路就不同。很明显,当某阶
段的起点给定时,它直接影响着后面各阶段的行进路线和整个路线的长短,而后 面各阶段的路线的发展不受这点以前各阶段的影响。故此问题的要求是:在各个
阶段选取一个恰当的决策,使由这些决策组成的一个决策序列所决定的一条路
线,其总路程最短。


三、 运用动态规划需符合的条件

任何思想方法都有一定的局限性,超出了特定条件,它就失去了作用。同理,动态规划也并不是万能的。那么使用动态规划必须符合什么条件呢?必须满足最优化原理和无后效性。

1 最优化原理

最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状
态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。

2 无后效性

“过去的步骤只能通过当前状态影响未来的发展,当前的状态是历史的总结”。这条特征说明动态规划只适用于解决当前决策与过去状态无关的问题。状态,出现在策略任何一个位置,它的地位相同,都可实施同样策略,这就是无后效性的内涵。
由上可知,最优化原理,无后效性,是动态规划必须符合的两个条件。


四 、动态规划的计算方法

对于一道题,怎样具体运用动态规划方法呢?

(1)首先,分析题意,考察此题是否满足最优化原理与无后效性两个条件。
(2)接着,确定题中的阶段,状态,及约束条件。
(3)推导出各阶段状态间的函数基本方程,进行计算。


应用举例:数字三角形(洛谷-P1216)

题目描述
观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

7 3 8
8 1 0

2 7 4 4
4 5 2 6 5
在上面的样例中,从 7 \to 3 \to 8 \to 7 \to 57→3→8→7→5 的路径产生了最大

输入格式
第一个行一个正整数 rr ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

输出格式
单独的一行,包含那个可能得到的最大的和。

输入输出样例
输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30

思路:

@顺推:

F[i+1][j] = MAX (F[i][j] + a[i+1][j]);

F[i+1][j+1] = MAX (F[i][j] + a[i+1][j+1]);

@ 逆推:

F[i][j] = MAX (F[i-1][j], F[i-1][j-1]) + a[i][j]; (注意!逆推时要注意边界情况! )

代码如下:
1、顺推:

//T2:数字金字塔-顺推(有点类似于记忆化搜索的思路)
//d数组储存顺序:记录从顶端向底部走的路径最优值(自顶向下)#include
#include
using namespace std;
int a[1005][1005];//储存数塔
int d[1005][1005];//从该点到底端的最大数字和
int main()
{int i,j,n,ans;while(cin>>n){memset(d,-1,sizeof(d));for(i&#61;0;i<n;i&#43;&#43;)for(j&#61;0;j<&#61;i;j&#43;&#43;){cin>>a[i][j];}d[0][0]&#61;a[0][0];for(int i&#61;0;i<n-1;&#43;&#43;i)for(int j&#61;0;j<&#61;i;&#43;&#43;j)//d数组为最优值路径&#xff08;黑色金字塔&#xff0c;a为源数据数组&#xff08;紫色金字塔&#xff09;{//分别用最优值来更新左下方和右下方d[i&#43;1][j]&#61;max(d[i&#43;1][j],d[i][j]&#43;a[i&#43;1][j]);//和当前的f[i&#43;1][j]比较d[i&#43;1][j&#43;1]&#61;max(d[i&#43;1][j&#43;1],d[i][j]&#43;a[i&#43;1][j&#43;1]);//和当前的f[i&#43;1][j&#43;1]比较}//答案可能是最后一行的任意一个&#xff0c;所以把最后一行搜索一遍&#xff0c;最大的赋给ansans&#61;0;for(int i&#61;0;i<n;i&#43;&#43;)ans&#61;max(ans,d[n-1][i]);cout<<ans<<endl;for(int i&#61;0;i<n;&#43;&#43;i){for(int j&#61;0;j<&#61;i;&#43;&#43;j){cout<<d[i][j]<<" ";}cout<<endl;}}return 0;
}

2、逆推

//数字金字塔-逆推
//d数组储存顺序&#xff1a;记录从顶端向底部走的路径最优值&#xff08;自顶向下&#xff09;
#include
#include
using namespace std;
int a[1005][1005];//储存数塔
int d[1005][1005];//从该点到底端的最大数字和
int main()
{int i,j,n,ans;while(cin>>n){memset(d,-1,sizeof(d));for(i&#61;0;i<n;i&#43;&#43;)for(j&#61;0;j<&#61;i;j&#43;&#43;){cin>>a[i][j];}//逆推&#xff08;自顶向下&#xff09;d[0][0]&#61;a[0][0];for(int i&#61;1;i<n;i&#43;&#43;){d[i][0]&#61;d[i-1][0]&#43;a[i][0];//最左的位置没有左上方d[i][i]&#61;d[i-1][i-1]&#43;a[i][i];//最右的位置没有右上方for(int j&#61;0;j<&#61;i;j&#43;&#43;)//在左上方和右上方取较大的d[i][j]&#61;max(d[i-1][j-1],d[i-1][j])&#43;a[i][j];}//答案可能是最后一行的任意一个&#xff0c;所以把最后一行搜索一遍&#xff0c;最大的赋给ansans&#61;0;for(int i&#61;0;i<n;i&#43;&#43;)ans&#61;max(ans,d[n-1][i]);cout<<ans<<endl;;for(int i&#61;0;i<n;&#43;&#43;i){for(int j&#61;0;j<&#61;i;&#43;&#43;j){cout<<d[i][j]<<" ";}cout<<endl;}}return 0;
}

附注&#xff1a;

动态规划相比较于深度搜索算法是一种高效算法。若能成功运用&#xff0c;必会使程序效率&#xff0c;无论时间还是空间&#xff0c;都有着质的飞跃。

掌握好动态规划&#xff0c;关键还是在于理解动态规划算法的基础上&#xff0c;多找一些相关的题进行练习。


推荐阅读
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
author-avatar
xz7777
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有