算法导论-动态规划(钢条切割问题)
写下文章来记录下自己学习算法导论的笔记
文章目录
- 写下文章来记录下自己学习算法导论的笔记
- 动态规划的目的
- 设计动态规划算法
- 钢条切割问题
- 问题描述
- 刻画问题结构(建立方程)
- 递归方程建立
- 带备忘录的自顶向下法
- 自底向下的方法
- 如何保留切割方案
- 源代码
动态规划的目的
求出最优子结构
设计动态规划算法
1.刻画一个最优解的结构特征
2.递归定义最优解的值
3.计算最优解的值
4.利用计算出的信息构造一个最优解
钢条切割问题
问题描述
Serling公司购买长钢条,将其切割为短钢条出售。切割工序本身没有成本支出。公司管理层希望知道最佳的切割方案。
假定我们知道Serling公司出售一段长度为i英寸的钢条的价格为p;(i=1,2,…,单位为美元)。钢条的长度均为整英寸。表1给出了一个价格表的样例。
钢条切割问题是这样的:给定一段长度为n英寸的钢条和一个价格表p;(i=1,2,…,n),求切割钢条方案,使得销售收益r。最大。注意,如果长度为n英寸的钢条的价格pn足够大,最优解可能就是完全不需要切割。
刻画问题结构(建立方程)
递归方程建立
书中的解释有一点绕,其实递归的思路就是,怎么样,切一刀(可以不切),使得当前的钢条的价格最高(所以此处的i的取值范围到了n(右边什么都不切)),由于自顶向下的递归较为好理解,所以我会用这种思路来进行解释。
PS:由于问题中的范围只有1-10,所以默认其他长度的值为0.
我们现在不是要切一刀钢条吗,编程思想:我挨个切一刀,选出其中获益最大的一刀。好了,现在不就有一个问题,也是我有点难绕过来的一个点,那就是我如何保证我这一刀切下来的钢条获益最大,没事,一刀不够,再来几刀,切下来的继续切,最后切到0,或者人为给一个出口,再一步一步返上来。
关于递归的运算量-指数级递增,为啥,重复算了很多遍,看下图
下面来上代码(java)
class Solution{public int CUT_RUD(int[] p, int n){//n-代表切掉的量if (n == 0) {return 0;}int q=0;for (int i = 1; i <= n; i++) {q=Math.max(q,p[i]+CUT_RUD(p,n-i));}return q;}}
小细节:这个数组p[]-是人为传入的参数,也就是钢条的收益值,需要注意一下下标,会在文末放入完整的代码
带备忘录的自顶向下法
如若其名所示,该方法其实是递归的改进,就是加入了一个数组来减小递归的运算量(先查后算),可以分成两个函数来写,也可以合并到一起,我根据书上的思路来的,结构更加清晰,第一个函数初始化存表r[],第二个函数用来计算,这种结构也方便用来存储切割方法。
//________________________带有备忘录的自顶向下发top-down with memoization,递归形式-先查,再存____________________________________________________
class Solution{public int MEMOIZED_CUT_RUD(int[] p,int n){if (n < 0) {return 0;}int[] r=new int[n+1];//重新声明空间for (int i = 0; i <= n; i++) {r[i]=-9999;}return MEMOIZED_CUT_RUD_AUX(p,n,r);
}
private int MEMOIZED_CUT_RUD_AUX(int[] p,int n,int[] r){//p[]-利润对应的数组,n-所切的数组,r[]放入已计算的数组,当前钢条数能代表的最大利润if(r[n]>=0)return r[n];int q=0;if (n == 0) {//切的长度为0q=0;}else {q = -999;for (int i = 1; i <= n; i++) {q=Math.max(q,p[i]+MEMOIZED_CUT_RUD_AUX(p, n-i, r));}}r[n]=q;return q;
}}
自底向下的方法
思想很简单,从0开始求,一步步累计上去,直到需要求的位。代码比较直接。
稍微有点难理解的就是为什么需要有两个循环,第一个循环-用来表示当前长度的利益最大值(从0开始),第二个循环就是求解子问题(怎样使得每一步的钢条最大化)
public int BOTTOM_UP_CUT_ROD(int[] p,int n){int[] r=new int[n+1];
int q=0;for (int j = 1; j <= n; j++) {q=-9999;for (int i = 1; i <= j; i++) {//max怎么切使得钢条利益最大化q=Math.max(q,p[i]+r[j-i]);}r[j]=q;//用来记录当前长度为j的利益最大值}
return r[n];
}
如何保留切割方案
就是在原有的基础上再增添一个数组,在比较最大值其作用时,传入标号,从程序可以看出来切割方案的保留是从小到大,有一些需要完善的地方就是无法把3段以上保留下来,毕竟是一维数组,不是多维的。
//————————————————————————————将方案也打印出来——————————————————————————————
private Map<String,Integer> EXTENDED_BOTTOM_UP_CUT_ROD(int[] p,int n){Map<String, Integer> map = new HashMap<String, Integer>();int[] r=new int[n+1];//用来记录int[] s=new int[n+1];//用来记录int q=0;for (int j = 1; j <= n; j++) {q=-9999;for (int i = 1; i <= j; i++) {//max怎么切使得钢条利益最大化if (q<(p[i]+r[j-i])){q=p[i]+r[j-i];s[j]=i;}}r[j]=q;//用来记录当前长度为j的利益最大值}map.put("最大收益",r[n]);map.put("切割方案",s[n]);return map;
}
public void PRINT_CUT_ROD_SOLUTION(int[] p,int n){Map<String, Integer> map = EXTENDED_BOTTOM_UP_CUT_ROD(p,n);System.out.println("最大收益:"+map.get("最大收益"));System.out.print("切割方案:");int i=1;while (n>0){if (i==1)System.out.print(map.get("切割方案"));else System.out.print("+"+map.get("切割方案"));n=n-map.get("切割方案");i=0;}
}//________________________带有备忘录的自顶向下发top-down with memoization,递归形式-先查,再存,带切割方案____________________________________________________public int MEMOIZED_CUT_RUD(int[] p,int n){if (n < 0) {return 0;}int[] r=new int[n+1];//重新声明空间int[] s=new int[n+1];for (int i = 0; i <= n; i++) {r[i]=-9999;}return MEMOIZED_CUT_RUD_AUX(p,n,r,s);}private int MEMOIZED_CUT_RUD_AUX(int[] p,int n,int[] r,int[] s){//p[]-利润对应的数组,n-所切的数组,r[]放入以计算的数组if(r[n]>=0)return r[n];int q=0;//重新声明空间if (n == 0) {//切的长度为0q=0;}else {q = -999;for (int i = 1; i <= n; i++) {int t=p[i]+MEMOIZED_CUT_RUD_AUX(p, n-i, r,s);if (q<t){q=t;s[n]=i;}}}for (int i = 0; i <= n; i++) {System.out.print(s[i]);System.out.print(" ");}System.out.println();r[n]=q;return q;}
源代码
//钢条切割问题
//问题描述:钢条切割问题是这样的:给定一段长度为n英寸的钢条和一个价格表p;(i=1,2,…,n),求切割钢条方案,使得销售收益rn最大。
// 注意,如果长度为n英寸的钢条的价格p。足够大,最优解可能就是完全不需要切割。
public class _15_1 {public static void main(String[] args) {Solution v=new Solution();int[] p={0};p=new int[40];p[0]=0;p[1]=1;p[2]=5;p[3]=8;p[4]=9;p[5]=10;p[6]=17;p[7]=17;p[8]=20;p[9]=24;p[10]=30;System.out.println(v.CUT_RUD(p,4));System.out.println(v.MEMOIZED_CUT_RUD(p,11));System.out.println(v.BOTTOM_UP_CUT_ROD(p,4));v.PRINT_CUT_ROD_SOLUTION(p,4);}
}
class Solution{//递归方法调用,递归的思想:将这根钢条切成2半,左半边不去管它,改变右半边的长度,从1-n(右半边钢条n-1-0),// 调用Max函数来递归求得何时才能使得钢条的分割成2半public int CUT_RUD(int[] p, int n){//n-代表切掉的量if (n == 0) {return 0;}int q=0;for (int i = 1; i <= n; i++) {q=Math.max(q,p[i]+CUT_RUD(p,n-i));}return q;}//________________________带有备忘录的自顶向下发top-down with memoization,递归形式-先查,再存____________________________________________________public int MEMOIZED_CUT_RUD(int[] p,int n){if (n < 0) {return 0;}int[] r=new int[n+1];//重新声明空间int[] s=new int[n+1];for (int i = 0; i <= n; i++) {r[i]=-9999;}return MEMOIZED_CUT_RUD_AUX(p,n,r,s);}private int MEMOIZED_CUT_RUD_AUX(int[] p,int n,int[] r,int[] s){//p[]-利润对应的数组,n-所切的数组,r[]放入以计算的数组if(r[n]>=0)return r[n];int q=0;//重新声明空间if (n == 0) {//切的长度为0q=0;}else {q = -999;for (int i = 1; i <= n; i++) {int t=p[i]+MEMOIZED_CUT_RUD_AUX(p, n-i, r,s);if (q<t){q=t;s[n]=i;}}}for (int i = 0; i <= n; i++) {System.out.print(s[i]);System.out.print(" ");}System.out.println();r[n]=q;return q;}//_____________________________________自底向上法_________________________________________________________public int BOTTOM_UP_CUT_ROD(int[] p,int n){int[] r=new int[n+1];int q=0;for (int j = 1; j <= n; j++) {q=-9999;for (int i = 1; i <= j; i++) {//max怎么切使得钢条利益最大化q=Math.max(q,p[i]+r[j-i]);}r[j]=q;//用来记录当前长度为j的利益最大值}return r[n];}//————————————————————————————将方案也打印出来——————————————————————————————private Map<String,Integer> EXTENDED_BOTTOM_UP_CUT_ROD(int[] p,int n){Map<String, Integer> map = new HashMap<String, Integer>();int[] r=new int[n+1];//用来记录int[] s=new int[n+1];//用来记录int q=0;for (int j = 1; j <= n; j++) {q=-9999;for (int i = 1; i <= j; i++) {//max怎么切使得钢条利益最大化if (q<(p[i]+r[j-i])){q=p[i]+r[j-i];s[j]=i;}}r[j]=q;//用来记录当前长度为j的利益最大值}map.put("最大收益",r[n]);map.put("切割方案",s[n]);return map;}public void PRINT_CUT_ROD_SOLUTION(int[] p,int n){Map<String, Integer> map = EXTENDED_BOTTOM_UP_CUT_ROD(p,n);System.out.println("最大收益:"+map.get("最大收益"));System.out.print("切割方案:");int i=1;while (n>0){if (i==1)System.out.print(map.get("切割方案"));else System.out.print("+"+map.get("切割方案"));n=n-map.get("切割方案");i=0;}}
}
"最大收益"));System.out.print("切割方案:");int i=1;while (n>0){if (i==1)System.out.print(map.get("切割方案"));else System.out.print("+"+map.get("切割方案"));n=n-map.get("切割方案");i=0;}}
}
算法导论-动态规划(钢条切割问题)相关推荐
- 算法导论 动态规划钢条切割问题 C语言
动态规划钢条切割问题 动态规划(dynamic programming)与分治法类似.分治策略将问题划分为互不相交的子问题,递归求解子问题,再将子问题进行组合,求解原问题.动态规划应用于子问题重叠的情 ...
- 算法导论-动态规划-钢条切割问题
文章目录 一.钢条切割定义 二.具体步骤 1.思考 2.代码思考 3.动态规划求解 4.伪代码 三:总结: 一.钢条切割定义 图为价格表 给定一段长度是n的钢条和一个价格表,求切割方案使得收益达到最大 ...
- 动态规划 — 钢条切割问题
动态规划: 什么是动态规划? 动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息.在求解任一子问题时 ...
- 动态规划-钢条切割(java)
数据结构与算法系列源代码:https://github.com/ThinerZQ/AllAlgorithmInJava 本文源代码:https://github.com/ThinerZQ/AllAlg ...
- 动态规划 -- 钢条切割问题
给定一段长度为n英寸的钢条和一个价格表p,求切割钢条方案(钢条的长度均为整英寸),使得销售收益最大. 我们可以计算出长度为n英寸的钢条共有2的(n-1)次方种不同的切割方案. 为解决规模为n的原问题, ...
- 动态规划—钢条切割问题与01背包问题
目录 1.钢条切割问题 第一种求最优解方案: 第二种求最优解方案: 第一种方法是 带备忘的自顶向下法 第二种方法是 自底向上法 2.01背包问题 1,穷举法(把所有情况列出来,比较得到 总价值最大的情 ...
- 算法导论例题——钢管切割
<算法导论>(CLRS)中第一个dp例题(rodcutting)的C++代码 #include<iostream> #include<vector> #includ ...
- 算法导论动态规划切割钢条
保存已经求得的子问题解 自底向上 #ifndef _MODEL_ #define _MODEL_ #include<vector> #include<map> using st ...
- 动态规划——钢条切割
有一根钢条,和他的长度价格表,真么样切割才能使得售出的钢条收益最大. 不考虑钢条的切割损耗. 输入n 表示钢条的长度 价格表p[i] 表示长度为i的钢条出售的价格 ------------------ ...
最新文章
- python拍7游戏代码_Python基础语法-7(小游戏)
- 字符串工具类---StringUtils
- Linux启动redis提示 /var/run/redis_6379.pid exists, process is already running or crashed
- LSGO软件技术团队2015~2016学年第十二周(1116~1122)总结
- C 语言程序设计基础不好,想10天考国二C语言程序设计证书,可能吗?
- python算法应用(四)——多维缩放
- WinAPI: Rectangle - 绘制矩形
- 系统编程之文件IO(一)——概述
- t450加固态硬盘教程_Thinkpad T450 超级笔记本 开箱更换SSD和内存
- 哪个计算机软件可以编辑动画文字,文字动画视频电脑版
- Web前端开发常用9个开源框架
- 一文搞懂深度学习所有工具——Anaconda、CUDA、cuDNN
- openproject_OpenProject入门
- 几行代码,把你的小电影全部藏好了!
- Raster Map光栅图 VS Vector Map矢量图
- 全球跨境电商平台有哪些?中国卖家占多少?
- Cesium加载各种互联网地图(一)
- 大数据揭秘诺奖评选“潜规则”
- FBI变态测试题,猜中一半的,赶紧去看看心理医生哦
- 51单片机16×16点阵led屏滚动显示+protues仿真+按键功能(史上最全)