动态规划原理解析

一、贪心算法通过一系列步骤构造问题的解,每一步对目前构造的部分解作一个扩展(往前推进,直至子问题的规模为零),直到获得问题的完整解为止。这个技术的核心是,所做的每一步选择都必须满足可行、局部最优、不可取消原则。

代表性算法有Dijkstra算法(当前最短路径),Prime算法(向前面构造的子树添加离树中顶点最近的顶点(邻接顶点))和Kruskal算法(贪婪的把最小权的边(顶点)纳入集合,保证不产生回路——不相交集ADT)。


二、动态规划的三大特征:

1)子问题重叠:一个问题的解,可以先分解为求解一系列子问题的解,同时包含重叠子问题(子问题不独立,没法进行分治;子问题不重叠,没有进行DP的必要,直接用普通的分治法即可)。最典型的例子就是斐波那契数列,重复计算的子问题很多,所以如果能把每次计算的子问题的解存储起来,下次如果需要求解同样的子问题时(重叠),我们就可以直接查表(在这里表现为一维数组)取值而不用计算。

还有一个爬楼梯的实际问题:有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法? 可以这样想,最后一次可以走一步也可以走两步,说明有两种可能,则 f (n) = f(n-1) + f(n-2) ,其中f(n)表示n级台阶的走法, f(n-1) 表示n-1级台阶的走法(登上n级台阶最后一次是走的一步), f(n-2) 表示n-2级台阶的走法(登上n级台阶最后一次是走的两步)。这里用到的就是无后效性和最优子结构。


2)最优子问题:子问题的最优解可以推出原问题的最优解(每个子问题都有一个最优解,下一阶段某个状态的最优解是由前面某一个状态(而非前面的那个状态)而迁移得到,关于这个问题可以用最长上升子序列问题来理解)

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

图1

例如图1中,若路线I和J是A到C的最优路径,则根据最优化原理,路线J必是从B到C的最优路线。这可用反证法证明:假设有另一路径J'是B到C的最优路径,则A到C的路线取I和J'比I和J更优,矛盾。从而证明J'必是B到C的最优路径。


3)无后效性

将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。无后效性最大的好处就是可以让我们只记最优状态,而不需记左右的状态。

DP是由某一阶段的某个或某些状态(而不管之前这个状态是如何得到)转移而来,抵达当前状态路径不唯一,仅是最终最优结果唯一(选择的结果)。

注意,说是“某一阶段”是准确的,因为DP的递推式中都有MAX或MIN的选择过程,这个选择是从众多状态转移中选择最优的一个(作为当前阶段的某一状态)。

换一种说法:动态规划方法代表了最优解问题的一般解法——我们自底向上(从叶子向根)构造子问题的解,对每一个子树的根,求出下面每一个叶子的值,并且以其中的最优值作为自身的值,其它的值舍弃(MAX或MIN来选择(舍弃——在选择的同时也必有舍弃))。

由定义,贪心算法是具有后效性的,一旦确定贪心策略后就是一条路走到底,没有多余的状态供给选择。那么下一个阶段的状态只能从当前的状态得到,而无法从以前各阶段的状态到现阶段现状态的转移中选择一个最优的(一个很好的例子就是最长上升子序列——动态规划)。显然,最终结果也必定唯一,即当前最优状态与之前的选取路径中全部节点都有关。

没得选(选择了,就放不回去,就必须沿着这条道走到底)和能选择最优(可以放回重新选,外在表现是维护的那张表),我认为是贪心和动归的最大区别。

例如:根据无后效性的定义我们知道,将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态来说,它以前各阶段的状态无法直接影响它未来的决策,而只能间接地通过当前的这个状态来影响。换句话说,每个状态都是历史的一个完整总结。以序列1,-1,2,-3,4,-5,6,-7为例,求解最长递增子序列。我们在找到4之后,并不关心4之前的两个值具体是怎样,因为它对找到6没有直接影响。因此,这个问题满足无后效性。http://m.blog.csdn.net/blog/ztj111/2748152

无论是floyd算法,最优二叉查找树,背包问题,还是最长公共子序列,它们的求解过程都是通过维护一个表(表现形式当然是一个数组,可以是二维的,也可以是一维的)记录到目前为止的所有可能的最优解,利用空间以换取时间。求解的过程就是向表中填值的过程!!(注意,约瑟夫问题并非动态规划)


三、不同点: 
贪心算法: 
1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留; 

2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解。 

动态规划算法: 

1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解(维护的表),这一步要求解的最优解可能要用到之前所有的最优解或任何一个最优解,而贪心只关心上一步的(最优---如Prime算法中每次选择dist值最小的顶点辐射)解;

2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解;

3.边界条件:即最简单的,可以直接得出的局部最优解。


四、总结

在动态规划算法中,每步所作的选择往往依赖于相关子问题的解(填表的空位要用到之前已填的值)。因而只有在解出相关子问题后,才能作出选择(如背包问题)。而在贪心算法中,仅在当前状态下作出最好选择,即局部最优选择。然后再去解作出这个选择后(如Prime算法中每次选择选择dist最小的顶点)产生的相应的子问题。贪心算法所作的贪心选择可以依赖于以往所作过的选择(如Prime算法中每次选择选择dist最小的顶点),但决不依赖于将来所作的选择,也不依赖于子问题的解(因为求解子问题是做出选择之后发生的事)。正是由于这种差别,动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为一个规模更小的子问题。


五、补充

1)算法世界里,要么用时间换空间,要么用空间换时间(时空权衡的典型应用——hash-table))

2)什么叫状态的组合?

每个阶段都有若干个状态。从第一个阶段到最后一个阶段(当前阶段的前一个阶段)的每个阶段中各取一个状态,把这些状态按照 阶段先后 串起来,就组合成了求取当前阶段最优状态的步骤,此即状态的组合。

显然,状态的组合数是指数级的。这种方法是搜索。如果动态规划的每个阶段的每个状态都是这么搜索而来,时间复杂度就很高,还好,我们是有“无后效性”这一杀手锏的。

3)动态规划、DAG最短路径和BFS的联系

动态规划→无环图最短路径(一层层向外扩展,既是广度优先搜索的做法,亦是动态规划的做法(子问题求解之后才能求解下一状态(其实也是一个子问题),也是c[i][j]的求解填表过程))←广度优先搜索(层序遍历)→拓扑排序(按任意一个拓扑排序序列的顺序来填——入度为0,说明它因为其包含的子问题都已经求解而可以求解)

在求解(整体问题)的最优解的时候,后面的步骤(不止后面一步,而是后面可能的所有步,这才是无后效性的精髓)选择只与当前状态有关,而与如何到达这个状态的步骤无关。 实质上,用有向无环图理解无后效性是最有效的最直观的方式(贪心算法是不会有这样的形式的),引出动归与贪心的区别: 贪心是先寻找(可能)最优的选择,再求解子问题——有后效性,而DP是先求解子问题,再从子问题的结果里选择(决策)使用哪个 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值