动态编程-杆切割自下而上算法(CLRS)解决方案不正确?

时间:2018-10-31 20:40:02

标签: algorithm dynamic-programming memoization bottom-up

对于“切棒”问题:

  

给出一根长度为n英寸的棒,并包含一组价格,其中包含所有小于n的尺寸的价格。确定通过切割杆并出售零件可获得的最大值。 [link]

算法简介(CLRS)第366页为自底向上(动态编程)方法提供了此伪代码:

1. BOTTOM-UP-CUT-ROD(p, n)              
2. let r[0 to n]be a new array .        
3. r[0] = 0                             
4. for j = 1 to n                       
5.     q = -infinity                    
6.     for i = 1 to j                   
7.         q = max(q, p[i] + r[j - i])  
8.     r[j] = q                         
9. return r[n]                          

现在,我在理解第6行背后的逻辑时遇到了麻烦。为什么他们要用max(q, p[i] + r[j - i])而不是max(q, r[i] + r[j - i])?由于这是一种自下而上的方法,因此我们将首先计算r[1],然后计算r[2], r[3]...,依此类推。这意味着在计算r [x]时,我们保证有r [x-1]。

r [x]表示我们可以为长度为x的一根棒获得的最大值(将其切成最大的利润后),而p [x]则为一根长度为x的棒的价格。第3-8行正在计算j = 1到n的值r[j],第5-6行通过考虑所有可能的切割来计算我们可以卖出长度为j的棒的最高价格。因此,在第6行中使用p [i]而不是r [i]有什么意义?如果在将长度切割为i后试图找到一根棒的最大价格,我们不应该加价r [i]和r [j-1]的关系?

我已经使用这种逻辑来编写Java代码,对于我尝试过的许多测试用例,它似乎都能提供正确的输出。在某些情况下,我的代码会产生不正确/无效的解决方案吗?请帮帮我。谢谢!

class Solution {
    private static int cost(int[] prices, int n) {
        if (n == 0) {
            return 0;
        }

        int[] maxPrice = new int[n];

        for (int i = 0; i < n; i++) {
            maxPrice[i] = -1;
        }

        for (int i = 1; i <= n; i++) {
            int q = Integer.MIN_VALUE;

            if (i <= prices.length) {
                q = prices[i - 1];
            }

            for (int j = i - 1; j >= (n / 2); j--) {
                q = Math.max(q, maxPrice[j - 1] + maxPrice[i - j - 1]);
            }

            maxPrice[i - 1] = q;
        }

        return maxPrice[n - 1];
    }


    public static void main(String[] args) {
       int[] prices = {1, 5, 8, 9, 10, 17, 17, 20};

        System.out.println(cost(prices, 8));
    }
}

2 个答案:

答案 0 :(得分:2)

它们应该等效。

CLRS方法背后的直觉是,他们假设最后一根杆的长度为i,因此其值恰好为p[i],因此他们试图找到单个“最后切割”。在此公式中,长度为i的“最后一块”不会被进一步切割,而长度为j-i的其余部分将被切掉。

您的方法将杆的所有分割都分为两部分,可以将其中的两个部分进一步切割。与CLRS方法相比,这认为是案例的超集。

这两种方法都是正确的,并且具有相同的渐近复杂度。但是,我认为CLRS解决方案更具“规范性”,因为它与DP解决方案的一种常见形式更紧密地匹配,在DP解决方案中,您只考虑了最后一个“事物”(在这种情况下,是最后一根未切割的杆)。

答案 1 :(得分:0)

我猜这两种方法都是正确的。

在我们证明它们都是正确的之前,先定义每种方法的确切作用

p [i] + r [j-i]将为您提供最大长度,您可以从长度为j的杆上获得该杆的最大值,该杆的尺寸为“ i”(无法进一步分割该杆)

r [i] + r [j-i]将为您提供最大长度i的棒的最大值,并且第一个切口的长度为“ i”(可以将两个块进一步分开)

现在考虑我们有一个长度为X的杆,并且解集将包含长度为k的段

由于k为0

在第二种方法中,您可以使用r [k] + r [X-k]找到相同的结果,因为我们知道r [k]将为> = p [k]

但是在您的方法中,由于您从两端切片了杆,因此可以获得更快的结果(一半的时间) 因此在您采用这种方法时,您可以将内部循环运行一半的长度就可以了。

但是我认为您的代码内部for循环中存在错误 应该是j> =(i / 2)而不是j> =(n / 2)