分享会之动态规划

一、简介

有这样一种具有特殊性的过程,其可以将被分成若干相互联系的阶段,在它的每个阶段都要做出决策,从而使整个过程达到最好的活动效果。但各个阶段决策的选取不是任意的,依赖于当前面临的状态,又影响以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线。

在求解这种活动过程的最优化结果的时候,通常有4种思路,①暴力穷举:将所有可能的决策序列枚举出来,然后比较每个序列的结果,得到最好的;②简单递归:自顶向下,以边界条件作为递归的结束;③备忘录算法:将每一阶段的决策保存下来,避免每得到一个决策序列都对每个阶段进行一次决策;④动态规划:利用自底向上的方式从最小的子问题开始向上逐渐推到得到最优解。

二、参考博客

https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653190796&idx=1&sn=2bf42e5783f3efd03bfb0ecd3cbbc380&chksm=8c990856bbee8140055c3429f59c8f46dc05be20b859f00fe8168efe1e6a954fdc5cfc7246b0&scene=21#wechat_redirect(极力推荐阅读这一篇,讲的非常直观易懂)

https://www.jianshu.com/p/69669c7bd69e

http://www.importnew.com/27444.html

三、动态规划

1、分类:

线性动规:拦截导弹,合唱队形,挖地雷,建学校,剑客决斗等;

区域动规:石子合并, 加分二叉树,统计单词个数,炮兵布阵等;

树形动规:贪吃的九头龙,二分查找树,聚会的欢乐,数字三角形等;

背包动规:01背包问题,完全背包问题,分组背包问题,二维背包,装箱问题,挤牛奶等。

2、基本思想:

大事化小,小事化了。把一个复杂的问题分阶段进行简化,逐步化简成简单的问题。

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。

动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引入时间因素,把它视为多阶段的决策过程,也可以使用动态规划方法方便地求解。

3、适用条件:

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

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

②无后效性将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。这就是无后向性,又称为无后效性。

③子问题的重叠性 动态规划将原来具有指数级时间复杂度的搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决冗余,这是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其它的算法。

4、基本要素:

最优子结构:一个大问题可以分解为怎样的子问题;

边界:最小的子问题,通常为迭代停止条件;

状态转移方程:由当前状态该如何转化为下一状态,某以问题与其子问题之间的关系。

5、求解步骤:

①根据问题,找到【最优子结构】。

把原问题从大化小的第一步,找到比当前问题要小一号的最好的结果,而一般情况下当前问题可以由最优子结构进行表示。

②确定问题的【边界】。

根据上述的最优子结构,一步一步从大化小,最终可以得到最小的,可以一眼看出答案的最优子结构,也就是边界。

③通过上述两步,通过分析最优子结构与最终问题之间的关系,我们可以得到【状态转移方程】。

6、复杂度分析:

用高空间复杂度换取时间复杂度降低。

算法实现是比较好考虑的。但有时也会遇到一些问题,而使算法难以实现。动态规划思想设计的算法从整体上来看基本都是按照得出的递推关系式进行递推,这种递推相对于计算机来说,只要设计得当,效率往往是比较高的,这样在时间上溢出的可能性不大,而相反地,动态规划需要很大的空间以存储中间产生的结果,这样可以使包含同一个子问题的所有问题共用一个子问题解,从而体现动态规划的优越性,但这是以牺牲空间为代价的,为了有效地访问已有结果,数据也不易压缩存储,因而空间矛盾是比较突出的。另一方面,动态规划的高时效性往往要通过大的测试数据体现出来(以与搜索作比较),因而,对于大规模的问题如何在基本不影响运行速度的条件下,解决空间溢出的问题,是动态规划解决问题时一个普遍会遇到的问题。

一个思考方向是尽可能少占用空间。如从结点的数据结构上考虑,仅仅存储必不可少的内容,以及数据存储范围上精打细算(按位存储、压缩存储等)。当然这要因问题而异,进行分析。另外,在实现动态规划时,一个我们经常采用的方法是用一个与结点数一样多的数组来存储每一步的决策,这对于倒推求得一种实现最优解的方法是十分方便的,而且处理速度也有一些提高。但是在内存空间紧张的情况下,我们就应该抓住问题的主要矛盾。省去这个存储决策的数组,而改成在从最优解逐级倒推时,再计算一次,选择某个可能达到这个值的上一阶段的状态,直到推出结果为止。这样做,在程序编写上比上一种做法稍微多花一点时间,运行的时效也可能会有一些(但往往很小)的下降,但却换来了很多的空间。因而这种思想在处理某些问题时,是很有意义的。

但有时,即使采用这样的方法也会发现空间溢出的问题。这时就要分析,这些保留下来的数据是否有必要同时存在于内存之中。因为有很多问题,动态规划递推在处理后面的内容时,前面比较远处的内容实际上是用不着的。对于这类问题,在已经确信不会再被使用的数据上覆盖数据,从而使空间得以重复利用,如果能有效地使用这一手段,对于相当大规模的问题,空间也不至于溢出(为了求出最优方案,保留每一步的决策仍是必要的,这同样需要空间)。

一般地说,这种方法可以通过两种思路来实现:一种是递推结果仅使用Data1和Data2这样两个数组,每次将Data1作为上一阶段,推得Data2数组,然后,将Data2通过复制覆盖到Data1之上,如此反复,即可推得最终结果。这种做法有一个局限性,就是对于递推与前面若干阶段相关的问题,这种做法就比较麻烦;而且,每递推一级,就需要复制很多的内容,与前面多个阶段相关的问题影响更大。另外一种实现方法是,对于一个可能与前N个阶段相关的问题,建立数组Data[0..N],其中各项为前面N个阶段的保存数据。这样不采用这种内存节约方式时对于阶段k的访问只要对应成对数组Data中下标为k mod (N+1)的单元的访问就可以了。这种处理方法对于程序修改的代码很少,速度几乎不受影响,而且需要保留不同的阶段数也都能很容易实现。

当采用以上方法仍无法解决内存问题时,也可以采用对内存的动态申请来使绝大多数情况能有效出解。而且,使用动态内存还有一点好处,就是在重复使用内存而进行交换时,可以只对指针进行交换,而不复制数据,这在实践中也是十分有效的。

7、例题:01背包问题

给定n种物品和一个背包。物品i的重量是w[i],其价值位v[i] ,背包的承重为W。问应该如何选择装入背包的物品,使得转入背包的物品的总价值为最大?

①暴力枚举:遍历所有结果(排列组合),找出价值最大的一个,时间复杂度为指数级别,O(2^N)。

②简单递归:

1、既然是从大到小,不断调用状态转移方程,那么就可以用递归。

2、递归的时间复杂度是由阶梯数和最优子结构的个数决定的。不同的问题,用递归的话可能效果会大不相同。

3、在阶梯问题,最少找零问题中,递归的时间复杂度和空间复杂度都比动归方法的差, 但是在国王与金矿的问题中,递归的时间复杂度和空间复杂度都比动归方法好。这是需要注意的。

问题分析:每个物品都只有两种状态,放入背包,不放入背包,所以每次只要取出两种情况下背包较重的即可,即总价值V ( i, Wi ) = max ( V ( i - 1, Wi ), V ( i - 1, Wi – w[i] ) + v[i] ),其中Wi为剩余可用容量。

总结得出包括边界在内的状态转移方程:

V ( 1, W1 ) = 0                                        w[1] > W

V ( 1, W1 ) = v[1]                                      w[1] <= W1

V ( i, Wi ) = V ( i – 1, Wi )                                w[i] > Wi

V ( i, Wi ) = max ( V ( i - 1, Wi ), V ( i - 1, Wi – w[i] ) + v[i] )   w[i] <= Wi

w[8] = [4, 3, 2, 5, 1, 2, 3, 1]
v[8]=  [3,
4, 1, 4, 2, 4, 5, 6]
W = 10

备忘录算法:

1、在阶梯数N比较多的时候,递归算法的缺点就显露出来了:时间复杂度很高。如果画出递归图(像二叉树一样),会发现有很多很多重复的节点。然而传统的递归算法并不能识别节点是不是重复的,只要不到终止条件,它就会一直递归下去。

2、为了避免上述情况,使递归算法能够不重复递归,就把已经得到的节点都存起来,下次再遇到的时候,直接用存起来的结果就行了。这就是备忘录算法。

3、备忘录算法的时间复杂度和空间复杂度都得到了简化。

动态规划:

1、上述的备忘录算法,尽管已经不错了,但是依然还是从最大的问题,遍历得到所有的最小子问题,空间复杂度是O(N)。

2、为了再次缩小空间复杂度,我们可以自底向上的构造递归问题,通过分析最优子结构与最终问题之间的关系,我们可以得到【状态转移方程】。

然后从最小的问题不断往上迭代,即使一直到最大的原问题,也是只依赖于前面的几个最优子结构。这样,空间复杂度就大大简化。也就得到了正经的动归算法。


1


2


3


4


5


6


7


8


9


10


4


3


3


3


3


3


3


3


3


4


4


4


4


7


7


7


7


2


1


4


4


5


5


7


7


8


8


5


1


4


4


5


5


7


8


8


9


1


2


2


4


6


6


7


7


9


10


10


2


2


4


6


6


8


10


10


10


11


13


3


2


4


6


7


9


11


11


13


15


15


1


6


8


10


12


13


15


17


17


19


21

此表格第一行代表背包剩余容重量,第一列代表第i个物体的重量,其余代表价值量。由状态转移方程可以看出,当考虑第i个物体时背包的状态只与考虑过第i - 1个物体的状态有关,即表中除第一行外的每一行都是由上一行得到的,所以可以从第一行开始不断迭代得到最后一行,即考虑第i个物体时背包所有可能的状态,第8行第10列即为问题中所求的最佳状态。

Q&A:大家对于备忘录算法的自顶向下和动态规划的自底向上的思想还存在疑惑。

原文地址:https://www.cnblogs.com/bupt213/p/10871276.html

时间: 2024-10-12 07:17:50

分享会之动态规划的相关文章

浅谈我对动态规划的一点理解---大家准备好小板凳,我要开始吹牛皮了~~~

前言 作为一个退役狗跟大家扯这些东西,感觉确实有点...但是,针对网上没有一篇文章能够很详细的把动态规划问题说明的很清楚,我决定还是拿出我的全部家当,来跟大家分享我对动态规划的理解,我会尽可能的把所遇到的动态规划的问题都涵盖进去,博主退役多年,可能有些地方会讲的不完善,还望大家多多贡献出自己的宝贵建议,共同进步~~~ 概念 首先我们得知道动态规划是什么东东,百度百科上是这么说的,动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process

算法导论_第十六章_动态规划_creatshare分享会

动态规划 注:该篇为本人原创,转载请注明出处:http://blog.csdn.net/chudongfang2015/article/details/51590817--开心 -.- 个人对动态规划的理解: 1.动态规划是一个付出额外空间来节省时间,就是所谓的空间换时间. 2.动态规划储存每个状态的最优解. 3.动态规划是用来把子问题的结果储存下来,再次用到的时候就不必再进行重复计算. 算法导论对动态规划的解释: 动态规划和分治方法相似,都是通过组合子问题的解来求解原问题,分治方法将问题划分为

第七篇 动态规划

今天跟大家分享下算法思想中比较难的一种"动态规划",动态规划给人像是作战时常用的“迂回战术”,或者说是 游击战,在运动中寻找突破口. 一: 思想 首先要了解”动态规划“,必须先知道什么叫做”多阶段决策“,百科里面对这个问题解释的很全,我就load一段出来, 大家得要好好品味,好好分析. 上面图中最后一句话就定义了动态规划是要干什么的问题. 二:使用规则 现在我们知道动态规划要解决啥问题了,那么什么情况下我们该使用动态规划呢? ①  最优化原理(最优子结构性质): 如果一个问题的最优策略

动态规划学习中的一道题目

记得初中时候的一篇文章说,做学问,必须要有学和问两个方面. 做了一些动态规划题目之后偶然看到这个介绍动态规划的文章.然后遇见第一道题目就卡壳. 经过反思文章以及自己思考,总算对题目有了一些理解.下面分享给大家,初学者们看到这个题目不至于太过茫然——像我一样. 工厂生产某种产品,每单位(千件)的成本为1(千元),每次开工的固定成本为3(千元),工厂每季度的最大生产能力为6(千件).经调查,市场对该产品的需求量第一.二.三.四季度分别为        2,3,2,4(千件).如果工厂在第一.二季度将

算法学习之动态规划(求矩阵连乘最小相乘次数)

基本思想:动态规划算法与分治法类似,其基本思想是将带求解的问题划分成若干个独立子问题,根据求得子问题的解合并而得到原问题的解.而动态规划划分的子问题往往不是相互独立的,因此若采用同分治法相同的求解问题的方法会导致大量的子问题被重复计算,为了避免这种情况发生,我们可以用一个表来记录我们求得的子问题的解,无论该子问题的解以后是否会用到,只要被计算,就将其填入表中.这便是动态规划的基本思想. 求解的基本步骤: (1)找出最优解的性质,并刻画其结构特征. (2)递归的定义最优值. (3)以自底向上的方式

【转】牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结

基础篇:操作系统.计算机网络.设计模式 一:操作系统 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式.(一定要会写生产者.消费者问题,完全消化理解) 5. 线程的实现方式. (也就是用户线程与内核线程的区别) 6. 用户态和核心态的区别. 7. 用户栈和内核栈的区别. 8. 内存池.进程池.线程池.(c++程序员必须掌握) 9. 死锁的概念,导致死锁的原因. 10. 导致死锁的四个必要条件. 11. 处理死锁

动态规划0-1背包问题

最近看了一些简单的动态规划方面的例题 在学习的过程中发现 有的问题虽然不难 但是第一次看还是会有些问题 所以把自己弄0-1背包的问题拿出来给大家分享 不喜勿喷 网上资源特别多 讲解什么的就算了 其他人画的图都不错 递推关系: 设所给0-1背包问题的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,-,n时0-1背包问题的最优值.由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式: <!--[endif]--> 上式此时背包容量为j,可选择物品为i.此时

【转】什么是动态规划?动态规划的意义是什么

https://www.zhihu.com/question/23995189 徐凯强 Andy 永远好奇 赵劼 . 空明流转 等 1818 人赞同了该回答 动态规划中递推式的求解方法不是动态规划的本质. 我曾经作为省队成员参加过NOI,保送之后也给学校参加NOIP的同学多次讲过动态规划,我试着讲一下我理解的动态规划,争取深入浅出.希望你看了我的答案,能够喜欢上动态规划. 0. 动态规划的本质,是对问题状态的定义和状态转移方程的定义.引自维基百科 dynamic programming is a

经典算法之动态规划--求最大公共子序列

作为新人,之前对C,C++了解的比较少,关于算法方面更是一窍不通,但最近却痴迷上了算法,哪怕是前辈们不屑一顾的东东,我弄明白了后都会欣喜若狂! 今天将遇到的问题和java实现贴出来和同为新人的博友分享,老鸟可以可以直接关网页了. 定义: 子序列:一个给定序列的子序列是再该序列中删去若干元素后得到的序列.即:给定{x1,x2,...,xm}和Z={z1,z2,...,zk},X的子序列是指存在一个严格递增下表序列{i1,i2,...ik} 使得对所有的j=1,2,...k,都有zj=xij.例如: