动态规划之钢条 切割

  1. 问题描述
    假设有长度为n寸的钢管,我们可以切割这段钢管以获得最大的利益(假设切割钢管无花费),价格表pi已知,问如何切割才能是销售收益rn最大。
    钢条价格表
  2. 解决方案
    对于这个问题我们可以使用递归的方式来解决。
    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[n] >= 0)
            return r[n];
        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[n] = 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[n];
    }

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

  1. 总结
    动态规划个递归十分相似,动态规划的子问题是可以重复的,递归的子问题一般是规模逐渐减小的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值