算法学习之动态规划(一)
2016-04-11 21:09
260 查看
动态规划的两个条件是最优子结构和子问题重叠。
最优子结构:一个问题的最优解包含其子问题的最优解。换句话说,用子问题的最优解可以构造原问题的最优解。例如钢条切割问题。
子问题重叠:子问题空间必须足够小,问题的递归算法会反复地求解相同的子问题。如背包问题。
动态规划求解时的方法:带备忘的自顶向下法、自底向上法。
我理解的带备忘的自顶向下法就是比如需要的是子问题的最小值,然后在存储结果的数组中先赋成无穷大,然后在从上到下递归时,若没有这个值,就采取递归来计算它(通常需要遍历所有的情况取最小值);若这个值已经在数组中保存,就直接利用它。“备忘”也就是这个存储之前计算结果的数组。
个人认为自底向上法更好理解一些,即从最小的子问题出发,一步一步将所有的子问题都求解,存在数组中,最后利用这些已经求解的子问题计算出原问题的最优解。
步骤:
1.刻画一个最优解的结构特征。通常也就是将父问题进行划分,看是否满足最优子结构。
2.递归定义最优解的值。一般是将递归式写出来,将m[i,j]用m[i-1,j]或另外的参数之类的表示出来,可能还要分i==j和i < j的条件。
3.用递归式计算最优解的值。
4.用上面的方法构造一个最优解。
钢条切割问题:给定一段长度为n英寸的钢条和一个价格表pi(i=1,2,……,n),求钢条切割方案,使得销售收益rn最大。注意,如果长度为n英寸的钢条的价格pn足够大,最优解可能就是完全不需要切割。
首先,我们需要确定这个问题满足最优子结构。让我们来这样想:将钢条从左边切割下一段长度为i的一段,剩下右边长度为n-i的一段可以递归来进行切割。也就是对左边进行长度为0-n的遍历,选取最大的,即为最优解。
递归式如下:
rn = max{pi + r(n-i)}(1<=i<=n)
算法:
1.自底向上法(迭代) 用r[0..n]保存收最优收益,用s[0..n]来保存第一段切割长度
2.带备忘的自顶向下法 (递归)
具体C代码如下:
最优子结构:一个问题的最优解包含其子问题的最优解。换句话说,用子问题的最优解可以构造原问题的最优解。例如钢条切割问题。
子问题重叠:子问题空间必须足够小,问题的递归算法会反复地求解相同的子问题。如背包问题。
动态规划求解时的方法:带备忘的自顶向下法、自底向上法。
我理解的带备忘的自顶向下法就是比如需要的是子问题的最小值,然后在存储结果的数组中先赋成无穷大,然后在从上到下递归时,若没有这个值,就采取递归来计算它(通常需要遍历所有的情况取最小值);若这个值已经在数组中保存,就直接利用它。“备忘”也就是这个存储之前计算结果的数组。
个人认为自底向上法更好理解一些,即从最小的子问题出发,一步一步将所有的子问题都求解,存在数组中,最后利用这些已经求解的子问题计算出原问题的最优解。
步骤:
1.刻画一个最优解的结构特征。通常也就是将父问题进行划分,看是否满足最优子结构。
2.递归定义最优解的值。一般是将递归式写出来,将m[i,j]用m[i-1,j]或另外的参数之类的表示出来,可能还要分i==j和i < j的条件。
3.用递归式计算最优解的值。
4.用上面的方法构造一个最优解。
钢条切割问题:给定一段长度为n英寸的钢条和一个价格表pi(i=1,2,……,n),求钢条切割方案,使得销售收益rn最大。注意,如果长度为n英寸的钢条的价格pn足够大,最优解可能就是完全不需要切割。
首先,我们需要确定这个问题满足最优子结构。让我们来这样想:将钢条从左边切割下一段长度为i的一段,剩下右边长度为n-i的一段可以递归来进行切割。也就是对左边进行长度为0-n的遍历,选取最大的,即为最优解。
递归式如下:
rn = max{pi + r(n-i)}(1<=i<=n)
算法:
1.自底向上法(迭代) 用r[0..n]保存收最优收益,用s[0..n]来保存第一段切割长度
r[0] = 0 for j = 1 to n q = -∞ for i = 1 to j //q = max{q, pi+r[j-i]} if q < pi+r[j-i] q = pi+r[j-i] s[j]=i //用来保存第一段切割长度 r[j] = q
2.带备忘的自顶向下法 (递归)
r[0] = 0 for i = 1 to n r[i] = -∞ f(p,n,r) f(p,n,r) if r >= 0 return r if n == 0 q = 0 else q = -∞ for i = 1 to n if q < pi+f(p,n-i,r) q = pi+f(p,n-i,r) s[j] = i r = q return q
具体C代码如下:
#include<stdio.h> #define M 1000 int p[11] = {0,1,5,8,9,10,17,17,20,24,30}; int r[M] = {0}; int s[M] = {0}; int BOTTOM_UP_CUT_ROD(int n)//自底向上法 { int i,j,q = 0; for(i = 0; i <= n; i++){ r[i] = -1;//负无穷大 s[i] = 0; } r[0] = 0; for(j = 1; j <= n; j++){ q = -1;//负无穷大 for(i = 1; i <= j; i++){ if(q < p[i]+r[j-i]){ q = p[i]+r[j-i]; s[j] = i; } } r[j] = q; } } int MEMOIZED_CUT_ROD(int n)//带备忘的自顶向下法 { int i,j; for(i = 0; i <= n; i++){ r[i] = -1;//负无穷大 s[i] = 0; } return MEMOIZED_CUT_ROD_AUX(n); } int MEMOIZED_CUT_ROD_AUX(int n) { int i,q; if(r >= 0) return r ; if(n == 0) q = 0; else{ q = -1;//负无穷大 for(i = 1; i <= n; i++){ if(q < p[i]+MEMOIZED_CUT_ROD_AUX(n-i)){ q = p[i] + MEMOIZED_CUT_ROD_AUX(n-i); s = i; } } } r = q; return q; } void print(int n) { printf("对应的切割方案为:"); while(n > 0){ printf("%d ",s ); n = n - s ; } printf("\n"); } int main() { int n,k; printf("请输入钢条长度:"); scanf("%d",&n); BOTTOM_UP_CUT_ROD(10); printf("自底向上:%d\n",r ); print(n); printf("自顶向下:%d\n",MEMOIZED_CUT_ROD(n)); print(n); }
相关文章推荐
- hadoop生态系统学习之路(十)MR将结果输出到hbase
- ACM-1000
- 循序渐进之Spring AOP(4) - Introduction
- Unicode基本概念
- ThinkPHP框架里隐藏index.php
- DPM v5源码阅读(未完成)
- 4/11
- VS2012通过makefile编译OpenGL红宝书的示例代码
- 10大协作办公工具:实现团队工作效率最大化
- zookeeper+kafka集群安装之中的一个
- ios纯代码下的起始页面配置方法
- 链表中间节点位置
- RobotFrameWork接口报文测试-----(三)demo的加强版(数据驱动测试)
- 汇编语言(王爽) 第7章 寻址方法
- webservice 入门笔记一
- ACM解题总结——HihoCoder1138
- windows/linux进程控制实验
- Warning C4819
- JavaScript中数组和字符串的方法以及互相转换
- AssetBundle整合资料深入理解