算法:动态规划

来源:互联网 发布:java 反射获取类的字段 编辑:程序博客网 时间:2024/05/17 04:33


1.首先来看看维基百科怎么定义的动态规划

引自wiki:Dynamic programming

In mathematics, management science, economics, computer science, and bioinformatics, dynamic programming (also known as dynamic optimization) is a method for solving a complex problem by breaking it down into a collection of simpler subproblems, solving each of those subproblems just once, and storing their solutions - ideally, using a memory-based data structure. The next time the same subproblem occurs, instead of recomputing its solution, one simply looks up the previously computed solution, thereby saving computation time at the expense of a (hopefully) modest expenditure in storage space. (Each of the subproblem solutions is indexed in some way, typically based on the values of its input parameters, so as to facilitate its lookup.) The technique of storing solutions to subproblems instead of recomputing them is called "memoization".

Dynamic programming algorithms are often used for optimization. A dynamic programming algorithm will examine the previously solved subproblems and will combine their solutions to give the best solution for the given problem. In comparison, a greedy algorithm treats the solution as some sequence of steps and picks the locally optimal choice at each step. Using a greedy algorithm does not guarantee an optimal solution, because picking locally optimal choices may result in a bad global solution, but it is often faster to calculate. Fortunately, some greedy algorithms (such as Kruskal's or Prim's for minimum spanning trees) are proven to lead to the optimal solution.

For example, in the coin change problem of finding the minimum number of coins of given denominations needed to make a given amount, a dynamic programming algorithm would find an optimal solution for each amount by first finding an optimal solution for each smaller amount and then using these solutions to construct an optimal solution for the larger amount. In contrast, a greedy algorithm might treat the solution as a sequence of coins, starting from the given amount and at each step subtracting the largest possible coin denomination that is less than the current remaining amount. If the coin denominations are 1,4,5,15,20 and the given amount is 23, this greedy algorithm gives a non-optimal solution of 20+1+1+1, while the optimal solution is 15+4+4.


In addition to finding optimal solutions to some problem, dynamic programming can also be used for counting the number of solutions, for example counting the number of ways a certain amount of change can be made from a given collection of coins, or counting the number of optimal solutions to the coin change problem described above.

Sometimes, applying memoization to the naive recursive algorithm (namely the one obtained by a direct translation of the problem into recursive form) already results in a dynamic programming algorithm with asymptotically optimal time complexity, but for optimization problems in general the optimal algorithm might require more sophisticated algorithms. Some of these may be recursive (and hence can be memoized) but parametrized differently from the naive algorithm. For other problems the optimal algorithm may not even be a memoized recursive algorithm in any reasonably natural sense. An example of such a problem is the Egg Dropping puzzle described below.

在文章的 第二段和第三段加黄背景的文字,第二段说明了与贪婪算法的不同并通过第三段的举例,同一个问题贪婪算法可能会得不到全局最优解,23=20+1+1+1,而动态规划是23=15+4+4得到全局最优解

还有在wiki Greedy algorithm 中有张图片:来说明贪婪算法有可能得不到全局最优解,但是幸运的是 Kruskal's or Prim's for minimum spanning trees 达到了全局最优解


2.然后我看  清华大学研究生公共课教材---数学系列---最优化理论与算法(第二版)陈宝林 编著

在最后第16章,以最短路线问题例介绍了动态规划,并定义了动态规划中的几个常用的术语。

1.阶段

2.状态

3.决策

4.策略

5.状态转移方程

6.指标函数

7.最优策略和最优轨线

在第二节提出了 R.Bellman的最优性原理:一个最优策略的子策略总是最优的


3. 算法导论中的动态规划

提到在动态规划方法的最优化问题中的两个要素:最优子结构和重叠子问题。

详细请看 算法导论P202

4.然后看知乎大神的解答

作者:徐凯强
链接:https://www.zhihu.com/question/23995189/answer/35324479

动态规划中递推式的求解方法不是动态规划的本质。

我曾经作为省队成员参加过NOI,保送之后也给学校参加NOIP的同学多次讲过动态规划,我试着讲一下我理解的动态规划,争取深入浅出。希望你看了我的答案,能够喜欢上动态规划。

0. 动态规划的本质,是对问题状态的定义状态转移方程的定义
引自维基百科
dynamic programming is a method for solving a complex problem bybreaking it down into a collection of simpler subproblems.
动态规划是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。
本题下的其他答案,大多都是在说递推的求解方法,但如何拆分问题,才是动态规划的核心。
拆分问题,靠的就是状态的定义状态转移方程的定义

1. 什么是状态的定义?

首先想说大家千万不要被下面的数学式吓到,这里只涉及到了函数相关的知识。

我们先来看一个动态规划的教学必备题:
给定一个数列,长度为N,
求这个数列的最长上升(递增)子数列(LIS)的长度.

1 7 2 8 3 4
为例。
这个数列的最长递增子数列是 1 2 3 4,长度为4;
次长的长度为3, 包括 1 7 8; 1 2 3 等.
要解决这个问题,我们首先要定义这个问题和这个问题的子问题。
有人可能会问了,题目都已经在这了,我们还需定义这个问题吗?需要,原因就是这个问题在字面上看,找不出子问题,而没有子问题,这个题目就没办法解决。

所以我们来重新定义这个问题:
给定一个数列,长度为N,
F_{k}为:以数列中第k项结尾的最长递增子序列的长度.
F_{1}..F_{N} 中的最大值.
显然,这个新问题与原问题等价。
而对于F_{k}来讲,F_{1} .. F_{k-1}都是F_{k}的子问题:因为以第k项结尾的最长递增子序列(下称LIS),包含着以第1..k-1中某项结尾的LIS。

上述的新问题F_{k}也可以叫做状态,定义中的“F_{k}为数列中第k项结尾的LIS的长度”,就叫做对状态的定义。
之所以把F_{k}做“状态”而不是“问题” ,一是因为避免跟原问题中“问题”混淆,二是因为这个新问题是数学化定义的。


对状态的定义只有一种吗?当然不是
我们甚至可以二维的,以完全不同的视角定义这个问题:
给定一个数列,长度为N,
F_{i, k}为:
在前i项中的,长度为k的最长递增子序列中,最后一位的最小值. 1\leq k\leq N.
若在前i项中,不存在长度为k的最长递增子序列,则F_{i, k}为正无穷.
求最大的x,使得F_{N,x}不为正无穷。
这个新定义与原问题的等价性也不难证明,请读者体会一下。
上述的F_{i, k}就是状态,定义中的“F_{i, k}为:在前i项中,长度为k的最长递增子序列中,最后一位的最小值”就是对状态的定义。


2. 什么是状态转移方程
上述状态定义好之后,状态和状态之间的关系式,就叫做状态转移方程。

比如,对于LIS问题,我们的第一种定义:
F_{k}为:以数列中第k项结尾的最长递增子序列的长度.
设A为题中数列,状态转移方程为:
F_{1} = 1 (根据状态定义导出边界情况)
F_{k}=max(F_{i}+1 | A_{k}>A_{i}, i\in (1..k-1)) (k>1)
用文字解释一下是:
以第k项结尾的LIS的长度是:保证第i项比第k项小的情况下,以第i项结尾的LIS长度加一的最大值,取遍i的所有值(i小于k)。

第二种定义:
F_{i, k}为:在数列前i项中,长度为k的递增子序列中,最后一位的最小值
设A为题中数列,状态转移方程为:
A_{i}>F_{i-1,k-1}F_{i,k}=min(A_{i},F_{i-1,k})
否则:F_{i,k}=F_{i-1,k}
(边界情况需要分类讨论较多,在此不列出,需要根据状态定义导出边界情况。)
大家套着定义读一下公式就可以了,应该不难理解,就是有点绕。

这里可以看出,这里的状态转移方程,就是定义了问题和子问题之间的关系。
可以看出,状态转移方程就是带有条件的递推式。

3. 动态规划迷思
本题下其他用户的回答跟动态规划都有或多或少的联系,我也讲一下与本答案的联系。

a. “缓存”,“重叠子问题”,“记忆化”:
这三个名词,都是在阐述递推式求解的技巧。以Fibonacci数列为例,计算第100项的时候,需要计算第99项和98项;在计算第101项的时候,需要第100项和第99项,这时候你还需要重新计算第99项吗?不需要,你只需要在第一次计算的时候把它记下来就可以了。
上述的需要再次计算的“第99项”,就叫“重叠子问题”。如果没有计算过,就按照递推式计算,如果计算过,直接使用,就像“缓存”一样,这种方法,叫做“记忆化”,这是递推式求解的技巧。这种技巧,通俗的说叫“花费空间来节省时间”。都不是动态规划的本质,不是动态规划的核心。

b. “递归”:
递归是递推式求解的方法,连技巧都算不上。

c. "无后效性",“最优子结构”:
上述的状态转移方程中,等式右边不会用到下标大于左边i或者k的值,这是"无后效性"的通俗上的数学定义,符合这种定义的状态定义,我们可以说它具有“最优子结构”的性质,在动态规划中我们要做的,就是找到这种“最优子结构”。
在对状态和状态转移方程的定义过程中,满足“最优子结构”是一个隐含的条件(否则根本定义不出来)。对状态和“最优子结构”的关系的进一步解释,什么是动态规划?动态规划的意义是什么? - 王勐的回答 写的很好,大家可以去读一下。

需要注意的是,一个问题可能有多种不同的状态定义和状态转移方程定义,存在一个有后效性的定义,不代表该问题不适用动态规划。这也是其他几个答案中出现的逻辑误区:
动态规划方法要寻找符合“最优子结构“的状态和状态转移方程的定义在找到之后,这个问题就可以以“记忆化地求解递推式”的方法来解决。而寻找到的定义,才是动态规划的本质。

有位答主说:
分治在求解每个子问题的时候,都要进行一遍计算
动态规划则存储了子问题的结果,查表时间为常数
这就像说多加辣椒的菜就叫川菜,多加酱油的菜就叫鲁菜一样,是存在误解的。

文艺的说,动态规划是寻找一种对问题的观察角度,让问题能够以递推(或者说分治)的方式去解决。寻找看问题的角度,才是动态规划中最耀眼的宝石!(大雾)



0 0
原创粉丝点击