动态规划理解

参看文章:通过金矿模型介绍动态规划

原文写的非常通俗易懂,我只是按自己的理解总结一下。

01背包问题

有10件物品,编号为0-9,第i件物品的体积为weight[i],价值为value[i]。如果有一个背包,容量为s。选取哪些物品装进背包里能使背包的装的东西总价值最大?

因为物品不能拆分,要么整个装,要么整个都不装,所以是01问题。

按平均价值是错误的

看到这个问题,可能首先会想到算每个物品的平均价值,先选平均价值最大的。但是这样算是错的。举个粒子:要把下面3个物品(体积,价值,平均价值)装容量为10的背包:

  物品A(3, 60,20), 物品B(4, 70,17.5), 物品C(5,80, 16)

  按平均价值算:最大平均价值算会选A,B 为 130 ,很显然这是错的。最大价值应该选B,C 150。

如果不是0-1问题,比如物品是一堆糖,一堆盐,是可以拆分,才能用平均价值计算。

暴力遍历组合

最简单粗暴的方法就是遍历所有可能的组合。每个物品都有两种选择:装或者不装。 n件物品总共就有 2种组合。

动态规划

再看看另一种思路, 我们把从i件物品中选择若干件放入容量为j的背包后的最大价值记为f(i,j)。假如背包的容量为20,物品为10件(编号从0-9),我们的任务就是要计算出 f(10,20)。

  先看最后一个物品(编号9,假如体积为3,价值为5),有两种选择:装 或者 不装。

  (1).如果选择装,并且装得下。那么背包现价值为 5, 背包还能在剩余的9个物品中装进体积为17的东西(20-3)。    背包总价值为:5+f(9,20-3)

  (2).如果不装,那么背包现价值为0, 背包还能在剩余的9个物品中装进体积为20的东西。  背包总价值为:f(9, 20)

  再从这两种选择中选取总价值最大的那一种,f(10, 20)= max{ f(9,20-3)+5,  f(9,20)  }。

  这里还有另外一种情况:如果选择装,但是发现根本装不下,没办法就只能选择不装了,变成了情况(2)。那么最大总价值就是不装的最大总价值 f(10,20)=f(9,20)

  

这个式子中有两个递归的子问题f(9,17)和f(9,20)。要得到f(10,20)的结果,还得继续算这俩子问题的结果。但是我们发现这俩个子问题和主问题完全是一个套路。比如说f(9,17),不就是在剩下的9个物品中选择一些装进容量为17的背包后的最大价值嘛。也按上面的套路来算好了。

  算f(9,17)。看剩下的这9个物品中的最后一个(也就是8号物品,假如体积为2,价值为3),也是两种选择:装 或者 不装。

  (1).如果选择装,并且装得下。那么背包现价值为 3, 背包还能在剩余的8个物品中装进体积为15的东西(17-2)。    背包最后的总价值为:3+f(8,17-2)。

  (2).如果不装,那么背包现价值为0, 背包还能在剩余的8个物品中装进体积为17的东西。  背包最后的总价值为:f(8, 20)。

  再从这两种选择中选取总价值最大的那一种,f(9, 17)= max{ f(8,17-2)+3,  f(8,17)  }。 又冒出两个更小点的子问题,还得继续往下算。。。

总结一下从i件物品中选择若干件放入容量为j的背包后的最大价值的递归的公式(背包状态转换方程):

  f(i,j)=max { f(i-1, j-weight(i))+ value(i),   f(i-1, j) } ;   条件  weight(i)<=j

  决策装不装第i个物品的时候另一种情况,如果weight(i)>j,也就是这件物品根本就装不进背包,我们就不考虑能装它的情况啦,背包的最大总价值就是不装该物那种情况的最大总价值。

  f(i,j)= f(i-1,j)   ; 条件 weight(i)>j

递归的子问题在一点点变小,很容易想到,最后一定终结在下面两种情况之一:

  (1)把全部物品都检查看了一遍了,已经没有物品了。 自然有 价值f(0, c)=0

  (2)还有物品,但是背包已经满了。 f(i, 0)=0。

其实也可以更早一点终结: 到只剩下一件物品(编号0)的时候,看还有多大空间的背包(j)。如果j>=weight(0),那么价值就是value(0),  如果j<weight(0),那么价值就是0。

如果直接这样计算,每个问题都划分成两个更小的问题。时间复杂度也是在O(2n)级别。 但实际上有很多f(i,j)值会反复计算多次,可以进一步优化让每个f(i,j)值只计算一次然后保存,以后就不需要再重复计算。然后,复杂度就变成了总共会有多少个子问题f(i,j)需要计算了。理论上说i可以取值0...i,j可以取值0...j,总共i*j+i+j+1种组合,子问题规模为O(ij)。但是很显然,实际的问题数量会远远小于这个理论值。

一般来说动态规划所需要的时间为 T=O(questingCount * chooseCount)。   questingCount(就是前面所说子问题的数量)= 可选对象的数量 * 资源总量。 chooseCount为每个子问题可以进行的选择数。背包问题中,一个物品要么装要么不装,所有chooseCount=2。

  

动态规划的特点(满足这些特点的问题就可以使用动态规划的思想):

  • 最优子结构:如果一个母问题可以分成几个子问题,确定了最优的子问题那么母问题也就是最优的。
  • 子问题重叠:母问题和子问题属于相同的模式,可以用同一个迭代式表示,不同点仅仅是参数。
  • 子问题独立:一个母问题的多个子问题只会选择一个作为实施方案,一般是相互独立的,不会互相影响。
  • 边界:问题逐渐变小,一定要能到达一个终止条件,也就是边界,否则就成死循环了。
  • 缓存中间数据,避免重复计算,可以极大优化性能。

题目一:买书

有一书店引进了一套书,共有3卷,每卷书定价是60元,书店为了搞促销,推出一个活动,活动如下:

如果单独购买其中一卷,那么可以打9.5折。

如果同时购买两卷不同的,那么可以打9折。

如果同时购买三卷不同的,那么可以打8.5折。

如果小明希望购买第1卷x本,第2卷y本,第3卷z本,那么至少需要多少钱呢?(x、y、z为三个已知整数)。

时间: 2024-10-12 14:52:23

动态规划理解的相关文章

POJ - 1125 Stockbroker Grapevine (动态规划理解floyd)

题目大意:有一个,想要在最短的时间內将一个谣言散发给所有人,但是他只能将这个谣言告诉给一个人,然后通过这个人传播出去.问,他应该告诉哪个人,让所有人都听到这个谣言的最短时间是多少 解题思路:这题很容易想到用floyd求出每个点之间的最短路. 做这题时,已经很久没做最短路的了,所以一时写不出floyd.发现自己太依赖模版了,所以在这里想写一下自己对floyd的理解(借鉴了这里写链接内容)好让自己下次不看模版也能想出来 设dp[i][j]为i到j的最短路,因为floyd有三成for,写起来的时候也知

动态规划之01背包问题(最易理解的讲解)

01背包问题,是用来介绍动态规划算法最经典的例子,网上关于01背包问题的讲解也很多,我写这篇文章力争做到用最简单的方式,最少的公式把01背包问题讲解透彻. 01背包的状态转换方程 f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] } f[i,j]表示在前i件物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值. Pi表示第i件物品的价值. 决策:为了背包中物品总价值最大化,第 i件物品应该放入背包中吗 ? 题目描述: 有编号分别为a,b

动态规划和分治法,贪心算法以及递归的再一次深刻理解和体会

每次体会算法都有新的感觉,刷题越多,对算法的理解感觉也就越深刻. 下面我们来重新体会下分治法,动态规划,贪心法,递归的理解. 1.分治法: 将问题分成单独的阶段,每个阶段互相不干扰很独立,如10米长的木棍,切成10段,每段去解决每一段的问题.(阶段没有关系) 2.贪心法 站在全局的角度,也是将问题堪称分为多个阶段,只不过阶段和阶段之间有一定的递进关系,如从5毛,1元,2毛,1毛,2元中,去找最少的钱币构成10块钱.首先是站在全局的角度,先从中取其最大值,为第一阶段,然后在从剩余的当中在找最大值,

从01背包问题理解动态规划---初体验

01背包问题具体例子:假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3.物品a1重量为3kg,价值为4:物品a2重量为4kg,价值为5:物品a3重量为5kg,价值为6.将哪些物品放入背包可使得背包中的总价值最大? 这个问题有两种解法,动态规划和贪婪算法.本文仅涉及动态规划. 先不套用动态规划的具体定义,试着想,碰见这种题目,怎么解决? 首先想到的,一般是穷举法,一个一个地试,对于数目小的例子适用,如果容量增大,物品增多,这种方法就无用武之地了. 其次,可以先把价值最大的物体放入

关于动态规划的理解

动态规划是个比较有趣的算法,第一次接触动态规划也是从一个比较特别的教程开始的,这里贴出原文地址http://blog.csdn.net/woshioosm/article/details/7438834 看完原文回到这里,其实我觉得很多像我这种C语言刚刚入门的人,只理解到了动态规划的转移方程,以原文中的例子为例: 当mineNum = 0且people >= peopleNeeded[mineNum]时 f(people,mineNum) = gold[mineNum] 当mineNum = 0

浅谈动态规划(个人理解)

动态规划,是常规的解决问题的一种方法,能解决的问题具有子问题的性质,即将大问题化成小问题进行分析解决,动态规划最重要的无非两点:状态和状态转移方程.所谓状态,指的是动态规划在化成每一个小问题时的状态,而状态转移方程,则是动态规划的关键:即将大问题化成小问题的方程:每个小问题的最优解都可以由这个方程得到,而大问题的最优解则是建立在小问题的最优解的基础上,下面我将通过一道经典题目来方便理解动态规划. 经典动规问题之0-1背包问题: 小明在旅行时偶然碰见一些钻石(假设有n个),而他只有一个背包,这个背

理解递归函数,和动态规划

作为一个CS学生,必须理解递归函数.这学期的Foundation of Computer里有一章讲到了递归,突然间有了新感悟. 以前理解递归,总会在脑海里模拟递归过程,直到返回为止.但常常内存不够,大脑宕机……T.T ------------------------------------------------------------------------------------------------------------------------------------ 举两个例子,一下

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

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

对动态规划算法的理解及相关题目分析

1.对动态规划算法的理解 (1)基本思想: 动态规划算法的基本思想与分治法类似:将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原问题的解.但是,与分治法不同的是,为了避免重复多次计算子问题,动态规划算法用一个表记录所有已解决的子问题的答案,不管该子问题以后是否被利用,只要它被计算过,就将其结果填入表中. (2)设计动态规划算法的步骤: ①找出最优解的性质,并刻画其结构特征 ②递归地定义最优值 ③以自底向上的方式计算最优值 ④根据计算最优值时得到的信息构造最优解 (3)