#C++初学记录(动态规划(dynamic programming)例题1 钞票)
浅入动态规划
dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems.
最近进行动态规划的学习,看到了一个很好的例子,现在把它记录下来仅供自我知识梳理
**1. 从一个生活问题谈起 [作者:阮行止](https://www.zhihu.com/question/23995189/answer/35429905)** 先来看看生活中经常遇到的事吧——假设您是个土豪,身上带了足够的1、5、10、20、50、100元面值的钞票。现在您的目标是凑出某个金额w,需要用到尽量少的钞票。 依据生活经验,我们显然可以采取这样的策略:能用100的就尽量用100的,否则尽量用50的……依次类推。 在这种策略下,666=6×100+1×50+1×10+1×5+1×1,共使用了10张钞票。 这种策略称为“贪心”:假设我们面对的局面是“需要凑出w”,贪心策略会尽快让w变得更小。能让w少100就尽量让它少100,这样我们接下来面对的局面就是凑出w-100。长期的生活经验表明,贪心策略是正确的。 但是,如果我们换一组钞票的面值,贪心策略就也许不成立了。 如果一个奇葩国家的钞票面额分别是1、5、11,那么我们在凑出15的时候,贪心策略会出错: 15=1×11+4×1 (贪心策略使用了5张钞票) 15=3×5 (正确的策略,只用3张钞票)
**题目认知**
显然这里使用贪心算法会导致程序运行结果出错,使用贪心策略,会优先选取11来吧w降为4,然后剩下的只能用4张1来凑,得出结果5。这显然是不符合题意的,暴力算法做该题显然是不行的,因为有无数种方法可以凑出某个金额w,这时时间复杂度是指数倍增加并且不可取。那么我们可以用DP(dynamic programming)来进行得出。动态规划的重点是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。将一个问题拆成几个子问题,分别求解这些子问题,即可推断出大问题的解,且满足无后效性、最优子结构性质。这里加入几个定义。
最优子结构:大问题的最优解可以由小问题的最优解推出,这个性质叫做“最优子结构性质。
无后效性:如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响。
那么我们对这个问题进行分解,因为钞票的票面额分别是1/5/11,那么w金额只与w-1、w-5、w-11的值有关,我们只需要关心最后凑出w所需的最少钞票数量,而不关心是怎么凑出w的。那么我们就可以用动态规划的思想再加上一点暴力算法:分别算出w-1,w-5,w-11所剩下的钞票数,在进行判断。