您的位置:首页 > 其它

动态规划之钢条 切割

2015-03-31 15:51 148 查看
问题描述

假设有长度为n寸的钢管,我们可以切割这段钢管以获得最大的利益(假设切割钢管无花费),价格表pi已知,问如何切割才能是销售收益rn最大。



解决方案

对于这个问题我们可以使用递归的方式来解决。

public static int CUT_ROD(int[] p, int n){
if(n == 0){
return 0;
}
int q = -1;
for(int i = 1; i <= n; i++){
q = Math.max(q, p[i] + CUT_ROD(p, n-i));
}
return q;
}


完成首次切割后,我们将两段钢条看成是两个独立的钢条切割问题,我们通过组合两个相关子问题的最优解来选取组合收益最大者。

虽然递归的方法可以求解该问题,但是仔细分析我们发现递归过程中我们求解的某些子问题是相同的,规模也是一样的。我们可以在求解的过程中将子问题的解保留下来,以便于下次碰到相同的子问题可以直接使用。

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] = -1;
}
return MEMOIZED_CUT_ROD_AUX(p, n, r);
}

public static int MEMOIZED_CUT_ROD_AUX(int[] p, int n, int[] r){
if(r
>= 0)
return r
;
int q = -1;
if(n == 0)
q = 0;
else {
for(int i = 1; i <= n; i++){
q = Math.max(q, p[i] + MEMOIZED_CUT_ROD_AUX(p, n-i, r));
}
}
r
= q;
return q;
}


上面这种方法称作带备忘的自顶向下发,此方法仍自然的递归形式编写过程,但过程会保存每个子问题的解,当需要一个子问题的解时,过程首先检查是否已经保存过此解。

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 = -1;
for(int j = 1; j <=i; j++){
q = Math.max(q, p[j] + r[i-j]);
}
r[i] = q;
}
return r
;
}


上面的方法称为自低向上法,该方法一般需要恰当定义子问题“规模”的概念,使得任何子问题的求解都只依赖于“更小的”子问题的求解。

总结

动态规划个递归十分相似,动态规划的子问题是可以重复的,递归的子问题一般是规模逐渐减小的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: