动态规划题目分析共21页文档
- 格式:ppt
- 大小:981.50 KB
- 文档页数:1
动态规划讲解大全含例题及答案动态规划讲解大全动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。
20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。
1957年出版了他的名著Dynamic Programming,这是该领域的第一本著作。
动态规划问世以来,在经济管理、生产调度、工程技术和最优控制等方面得到了广泛的应用。
例如最短路线、库存管理、资源分配、设备更新、排序、装载等问题,用动态规划方法比用其它方法求解更为方便。
虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。
动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。
不象前面所述的那些搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。
动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。
因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。
我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。
基本模型多阶段决策过程的最优化问题。
在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。
动态规划动态规划是运筹学的一个分支,它是解决多阶段决策过程最优化问题的一种方法。
该方法是由美国数学家贝尔曼(R.Bellman)等人在本世纪50年代初提出的。
他们针对多阶段决策问题的特点,提出了解决这类问题的“最优化原理”,并成功地解决了生产管理、工程技术等方面的许多实际问题,从而建立了运筹学的一个新分支——动态规划。
他的名著《动态规划》于1957年出版,该书是动态规划的第一本著作。
动态规划是现代企业管理中的一种重要决策方法,在工程技术、经济管理、工农业生产及军事及其它部们都有广泛的应用,并且获得了显著的效果。
动态规划可用于解决最优路径问题、资源分配问题、生产计划与库存问题、投资分配问题、装载问题、设备更新与维修问题、排序问题及生产过程的最优控制等。
由于它所具有独特的解题思路,在处理某些优化问题时,常常比线性规划或非线性规划方法更有效。
第一节动态规划的基本方法多阶段决策的实际问题很多,下面通过具体例子,说明什么是动态规划模型及其求解方法。
例1:最短路线问题某工厂需要把一批货物从城市A运到城市E,中间可经过B1 、B2、B3、C1、C2、C3、D1、D2等城市,各城市之间的交通线和距离如下图所示,问应该选择一条什么路线,使得从A到E的距离最短?下面引进几个动态规划的基本概念和相关符号。
(1)阶段(Stage)把所给问题的过程,按时间和空间特征划分成若干个相互联系的阶段,以便按次序去求每个阶段的解,阶段总数一般用字母n表示,用字母k表示阶段变量。
如例l中 (最短路线问题)可看作是n=4阶段的动态规划问题,k=2表示处于第二阶段。
(2)状态(State)状态表示每个阶段开始时系统所处的自然状况或客观条件,它描述了研究问题过程状况。
描述各阶段状态的变量称为状态变量,常用字母sk表示第k阶段的状态变量,状态变量的取值范围称为状态集,用Sk表示。
如例l中,第一阶段的状态为A(即出发位置)。
第二阶段有三个状态:B1 、B2、B3,状态变量s2=B2表示第2阶段系统所处的位置是B2。
动态规划总结——经典问题总结本文着重讨论状态是如何表示,以及方程是怎样表示的。
当然,还附上关键的,有可能作为模板的代码段。
但有的代码的实现是优化版的。
经典问题总结最长上升子序列(LIS)问题描述如下:设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。
求最大的m值。
这里采用的是逆向思维的方法,从最后一个开始想起,即先从A[N](A数组是存放数据的数组,下同)开始,则只有长度为1的子序列,到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]。
有了以上的思想,DP方程就呼之欲出了(这里是顺序推的,不是逆序的):DP[I]=MAX(1,DP[J]+1)J=0,1,...,I-1但这样的想法实现起来是)O(n^2)的。
本题还有更好的解法,就是O(n*logn)。
利用了长升子序列的性质来优化,以下是优化版的代码://最长不降子序const int SIZE=500001;int data[SIZE];int dp[SIZE];//返回值是最长不降子序列的最大长度,复杂度O(N*logN)int LCS(int n) { //N是DATA数组的长度,下标从1开始int len(1),low,high,mid,i;dp[1]=data[1];for(i=1;i<=n;++i) {low=1;high=len;while( low<=high ) { //二分mid=(low+high)/2;if( data[i]>dp[mid] ) {low=mid+1;}else {high=mid-1;}}dp[low]=data[i];if( low>len ) {++len;}}return len;}最长公共子序列(LCS)给出两个字符串a, b,求它们的最长、连续的公共字串。
动态规划解析第一题导弹拦截本题第一问实际上是给出数列a1..a n,求最长非递增序列的长度,{容易想到以n来划分子问题,即分别求a1..a n-1, a1..a n-2, …, a1,中最长非递增序列长度,但各级子问题之间不易建立转化关系}将子问题具体一些,我们可以用f[k]表示数列a1..a k中以a k结尾的最长非递增序列的长度,题目所求即为max{f[1..n]}。
转移方程为f[n]=max{f[k]}+1;(0<=k<n,a[n]<=a[k] )设a[0]= -maxint,f[0]=0;第二问可以用贪心做,设拦截前k个导弹用o2个系统,其最后拦截的高度分别为l[1]..l[o2],则拦截第k+1个导弹时,找能够拦截这枚导弹的系统中最后拦截高度最小的,若没有这样的系统则新增一个系统。
附源程序:const max = 10000;type arr = array[0..max]of integer;var d,l : arr;i,j,k,m,n,o1,o2,t : longint;procedure input;beginfillchar(d,sizeof(d),0);fillchar(l,sizeof(l),0);writeln('input:');i:=0;repeati:=i+1;read(d[i]);until eoln;t:=i;o1:=0; o2:=0;end;procedure output;beginwriteln('Output:');writeln(o1);writeln(o2);end;procedure main1;beginl[t]:=1;for i:=t-1 downto 1 do begink:=0;for j:=i+1 to t doif (l[j]>k)and(d[i]>=d[j]) then k:=l[j];l[i]:=k+1;end;for i:=1 to t doif l[i]>o1 then o1:=l[i];end;procedure main2;beginfor i:=0 to t do l[i]:=maxint;o2:=1;for i:=1 to t do begink:=0;for j:=1 to o2 doif (l[j]>=d[i])and(l[j]<=l[k]) then k:=j;if k=0 then begino2:=o2+1;k:=o2;end;l[k]:=d[i];end;end;begininput;main1;main2;output;end.第二题 石子合并设f[i,j](i<=j)表示将第i 堆到第j 堆石子合并为一堆所得的最大分数(最小时类似)。
TSP问题的动态规划解法第十七组:3103038028 郑少斌3103038029 王瑞锋3103038035 江飞鸿3103038043 韩鑫3103055004 唐万强1.TSP问题简介旅行商问题(Traveling Salesman Problem,简称TSP, 亦称为货单郎问题)可以描述为:对于N 个城市,它们之间的距离已知,有一旅行商要从某一城市走遍所有的城市,且每一城市只能经过一次,最后回到出发的城市,问如何选择路线可使他走过的路径最短。
这是一个典型的组合优化问题。
它有很强的现实意义,可以应用于交通运输,物资调配,旅游线路设置。
对于了解某个国家地理分布也有一定的现实意义。
这个问题的解法有很多种,在这里我们尝试使用最优控制中的动态规划的相关知识来进行求解。
2.TSP问题分析对于这个问题,我们首先想到的是应用穷举法进行解答,但是这个方法时间和空间的复杂度很高。
从表面上看,TSP 问题很简单,其实则不然。
对于N 个城市的TSP,存在的可能路径为(N-1)!/2条,当N较大时,其数量是惊人的。
计算每条路经都需求出N 个距离之和,这样各种路径及其距离之和的计算量正比与N!/2.用搜索法要求就规模大的TSP是不现实的。
例如使用1GFLOPs 次的计算机搜索TSP 所需的时间如下表所示 城市数7152050100200加法量 3105.2⨯ 11105.6⨯ 18102.1⨯ 64105.1⨯ 157105⨯ 37410搜索时间s 5105.2-⨯1.8h350yy 48105⨯ y 14210y 35810由上可知,对于这个问题采用穷举法进行解答是不现实的,这就要求我们采用其他的方法进行解答。
3. 其他求解TSP 问题的方法*贪心法a. 所谓贪心法,就是在组合算法中,将每一步都取局部最优的求解方法。
b. 下表表示用贪心法求解TSP 的过程。
先将各城市间的距离用行列式形式表示,主对角线上用∞表示。
常见动态规划题⽬详解1.爬楼梯题⽬描述:假设你正在爬楼梯。
需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。
你有多少种不同的⽅法可以爬到楼顶呢?注意:给定 n 是⼀个正整数。
⽰例 1:输⼊: 2输出: 2解释:有两种⽅法可以爬到楼顶。
1. 1 阶 + 1 阶2. 2 阶⽰例 2:输⼊: 3输出: 3解释:有三种⽅法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶2. 1 阶 + 2 阶3. 2 阶 + 1 阶实现代码:class Solution {public:int climbStairs(int n) {vector<int> a(n);a[0] = 1;a[1] = 2;if(n == 1){return 1;}if(n == 2){return 2;}for(int i = 2; i < n;i++){a[i] = a[i - 1] + a[i - 2];}return a[n - 1];}};2.变态跳台阶题⽬描述:⼀只青蛙⼀次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上⼀个n级的台阶总共有多少种跳法。
实现代码:class Solution {public:int jumpFloorII(int number) {if(number == 0){return 0;}int total = 1;for(int i = 1; i < number; i++){total *= 2;}return total;}};3.n年后⽜的数量题⽬描述:假设农场中的母⽜每年会产⽣⼀头⼩母⽜,并且永远不会死。
第⼀年农场中只有⼀头成熟的母⽜,第⼆年开始,母⽜开始⽣⼩母⽜,每只⼩母⽜三年之后成熟⼜可以⽣⼩母⽜,给定整数N,求N年后母⽜的数量。
实现代码:class solution{ public: int f(int n){ if(n < 1){ return 0; } if(n == 1|| n== 2||n == 3){ return n; } int res = 3; int pre = 2; int prepre = 1; int tmp1=0; int tmp2 = 0; for(int i = 4;i < n;i++){ tmp1 = res; tmp2 = pre; res = pre + prepre; pre = tmp1; prepre = tmp2; } return res; }};4.矩形覆盖题⽬描述:我们可以⽤2*1的⼩矩形横着或者竖着去覆盖更⼤的矩形。
力扣优秀题解——动态规划动态规划(Dynamic programming,简称DP)是一种常见的求解优化问题的方法。
它与分治算法类似,都是通过将大问题分解成若干个小问题来求解的。
不同的是,DP解决的问题通常是有重叠子问题和最优子结构特征的,即在求解过程中会反复计算相同的子问题,并且每个子问题都具有最优解,可以通过这些最优解推导出全局最优解。
力扣中的很多题目都可以使用动态规划来解决,比如最长公共子序列、股票买卖、打家劫舍等等。
下面针对这些题目进行详细解析。
一、最长公共子序列题目描述:给定两个字符串text1 和text2,返回它们的最长公共子序列。
如果不存在公共子序列,返回0。
示例:输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace",它的长度为 3。
解题思路:最长公共子序列问题是比较经典的DP问题。
设字符串text1和text2的长度分别为m 和n,令dp[i][j]表示text1[0:i]和text2[0:j]的最长公共子序列长度,为方便起见,text1和text2的下标从1开始。
当text1[i-1] == text2[j-1]时,dp[i][j] = dp[i-1][j-1] + 1,即text1[0:i-1]和text2[0:j-1]的最长公共子序列长度加上1。
当text1[i-1] != text2[j-1]时,dp[i][j] = max(dp[i-1][j], dp[i][j-1]),即考虑text1[0:i-1]和text2[0:j]的最长公共子序列长度与text1[0:i]和text2[0:j-1]的最长公共子序列长度,两者取最大值。
最终的答案即为dp[m][n]。
代码实现:class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: m, n = len(text1), len(text2) dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if text1[i - 1] == text2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[m][n]二、股票买卖题目描述:给定一个数组prices,其中prices[i]是一支给定股票第i天的价格。