动态规划钢条切割
Posted xucoding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划钢条切割相关的知识,希望对你有一定的参考价值。
简介
什么是动态规划
答:动态规划与分治法相似,都是通过组合子问题的解来求解原问题。他们之间的不同是,分治法将问题划分为互不相交的子问题,而动态规划应用于子问题重合的情况。使用分治法求解子问题重合的问题,会做许多不必要的工作,动态规划将已经求解的子问题保存到一张表格中,从而避免了反复求解重合子问题的情况。
动态规划常用来解决什么问题
答:最优化问题。最优化问题可以有很多可行解,每个解都有一个值,我们希望寻找具有最优值的解,最大或最小。我们称这样的解是问题的一个最优解(最优解可以有多个)。
设计动态规划算法的步骤
- 刻画一个最优解的结构特征;
- 递归的定义最优解;
- 计算最优解的值,通常采用自底向上的方法;
- 利用计算出的信息构造最优解;
问题
分析
从算法的角度来思考,我们如果要解决一个问题,只需要把这个问题的所有可能都列举出来。通过来检查每一种情况,来计算出一个最优的解。我们如何来穷举出所有的可能呢?
我们从钢条的最左端开始,在钢条长度为1的位置切割,那么问题的解即是r(n) = p[1] + r(n-1),我们看到问题的规模减小了,我们可以递归的解决子问题r(n-1)。一般的,r(n) = p[i] + r(n-i),i = 1,2,... n。
代码
/**
* 递归解法
* @param p
* @param n
* @return
*/
public static int cut_rod(int[] p, int n){
if(n == 0) return 0;
int q = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
q = Math.max(q, p[i] + cut_rod(p, n - i));
}
return q;
}
递归的解法求解了很多不必要的子问题,而我们可以将求解过的子问题记录下来。当遇到子问题时只需从表格中查找,这样就避免买子问题的重复计算。
/**
* 带备忘录的自顶向下递归解法
* @param p
* @param n
* @return
*/
public static int memoized_cut_rod(int[] p, int n){
int[] r = new int[n + 1];
for (int i = 0; i < r.length; i++) {
r[i] = Integer.MIN_VALUE;
}
return memoized_cut_rod_aux(p, n, r);
}
public static int memoized_cut_rod_aux(int[] p, int n, int[] r){
if(r[n] >= 0) return r[n];
int q;
if(n == 0){
q = 0;
}else {
q = Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
q = Math.max(q, p[i] + memoized_cut_rod_aux(p, n - i, r));
}
}
r[n] = q;
return q;
}
/**
* 自底向上的解法
* @param p
* @param n
* @return
*/
public static int bottom_up_cut_rod(int[] p, int n){
int[] r = new int[n + 1];
r[0] = 0;
for (int i = 1; i <= n; i++) {
int q = Integer.MIN_VALUE;
for (int j = 1; j <= i; j++) {
q = Math.max(q, p[j] + r[i - j]);
}
r[i] = q;
}
return r[n];
}
以上是关于动态规划钢条切割的主要内容,如果未能解决你的问题,请参考以下文章