Dynamic Programming学习笔记 (11) - 切棒子问题

221 阅读1分钟

切棒子问题与无限背包问题如出一辙,只是表达形式略有不同:给定一个长度为N的棒子,以及一个同样长度的数组,数组中的第i个元素代表从棒子上切下长度为i的一条所对应的价格,问整个棒子切完后所得价格总和的最大值。

实例如下

N = 8
price = {1, 5, 8, 9, 10, 17, 17, 20}

答案是22, 切下长度2(价格为5)和长度6(价格为17)

使用与无限背包问题相同的解题思路,给定一个长度k,我们可以使用如下的数学表达式

F(k)
 = 0, k=0
  = max of
        price[0] + F(k - 1),
        price[1] + F(k - 2),
        ...
        price[k- 1] + F(0),

这里F(k)返回的是棒子长度为k时的最大价格和。切下1个单元,得到价格为price[0],棒子长度减少1;切下2个单元,得到价格为price[2],棒子长度减少2,由此类推。所有可能的切法中的最大值就是F(k)的返回值。

我们使用一个一维数组作为DP存储,其下标就是从0到N的各个数字,依照上面的表达式从小到大依次计算DP数组的每个元素,最后DP[N]中的数值就是问题的最终答案。

Java代码如下

class Solution {
    public int cutRod(int price[],int n) {
        int[] dp = new int[n + 1];

        for (int i = 1; i <= n; i++) {
            int maxPrices = 0;

            for (int j = 0; j < i; j ++) {
                int p = price[j] + dp[i - j  -1];
                maxPrices = Math.max(maxPrices, p);
            }
            dp[i] = maxPrices;
        }

        return dp[n];
    }
}