【问题标题】:Rod cutting - recursive杆切割 - 递归
【发布时间】:2017-10-29 00:32:18
【问题描述】:

问题:http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/

我的代码在:http://ideone.com/HGXk3t

我尝试解决递归问题,但得到了意想不到的结果。 对于杆切割问题,我最多调用两个相同的递归函数:一个使用该索引,另一个不使用该索引的价格。 但答案不是它应该是的。 提前致谢。

#include<stdio.h>

// A utility function to get the maximum of two integers
int max(int a, int b) { return (a > b)? a : b;}

/* Returns the best obtainable price for a rod of length n and
   price[] as prices of different pieces */
int cutRod(int price[], int n, int i)
{
    if(n<1 || i==0)
        return 0;

    return max(price[i-1] + cutRod(price,n-(i+1),i), cutRod(price,n,i-1));
}

/* Driver program to test above functions */
int main()
{
    int arr[] = {17, 17, 1};
    int size = sizeof(arr)/sizeof(arr[0]);
    printf("Maximum Obtainable Value is %d\n", cutRod(arr, size, size));
    getchar();
    return 0;
}

【问题讨论】:

  • 使用 std:: 向量,std::max。不要使用 stdio.h 和 limits.h。
  • @Rahul——选择一种语言; C 和 C++ 不一样。
  • @manni66-- 发布的代码是 C。我认为这里不需要 limits.h,但为什么不应该使用 stdio.h?毕竟printf()需要。
  • limits.h 不需要,除非您使用 INT_MIN 作为算法的负权重。
  • 我删除了limits.h。我之前使用的是 INT_MIN,但后来删除了。

标签: c++ c recursion


【解决方案1】:

杆切割问题基本上说明了给定一根杆,我们可以切割成离散的增量,以及这些离散尺寸的杆的价格,我们如何切割杆,以便我们获得整体的最佳价格。在您的示例中,您将一个大小为 3 {17, 17, 1} 的数组传递给您的函数,根据我们的问题陈述,它表示一块大小为 1 的杆是 17 个单位,一块大小为 2 的值是 17 个单位,尺寸 3 的一块价值 1 个单位。显然,您的示例的最佳解决方案是将杆切成单个单元并出售。您提供的链接中的示例具有这样的价目表:{1,5,8,9,10,17,17,20}。对此的解决方案不太明显,需要更细致入微的方法来解决它。这种情况是递归解决方案显示其价值的情况。

您的解决方案似乎试图解决此问题的幼稚递归版本,其中我们不考虑您提供的链接中讨论的重叠子问题之类的事情。为了以天真的方式解决这个问题,您检查所有子问题并返回它们的最大值结果,然后将它们组合起来以找到全局最大值。例如,对于尺寸为 8 的杆,您需要找到尺寸为 7、6、5... 的杆返回的最高价格,并结合这些选项来找到全局最大值。您的解决方案没有找到并结合这些选项,这就是您没有得到正确结果的原因。检查和组合此问题的所有子问题的最直观方法是执行以下伪代码:

def cutRod(arr price[], int n)
   if(n <= 0)
     return 0;
   int max_val = -inf //set maximum value to negative infinity
   for(int i = 0; i<n; ++i)
     max_val = max(max_val, price[i] + cutRod(price, n-i-1));
   return max_val;

这基本上是您提供的链接中作为天真的示例给出的代码。它所做的是循环遍历给定尺寸的杆的所有可能价格选项,得出以给定价格出售所述尺寸的杆所返回的价值,以及杆的其余部分可能的最高价格。对于他们的示例 {1,5,8,9,10,17,17,20},代码将首先在位置 1 找到杆切割的最高价格,因此您将 price[0] 与 cutRod(price, 7 )。这会找到您可以出售尺寸为 7 的杆的最高价格,即 18(17 和 1),然后将 price[0] 添加到该价格,返回 19。此过程继续进行,直到您找到所有杆的最大值子问题,最终是 22。

如您所见,在此示例中,我们基本上检查了切杆场景的所有可能合理选项,如您上面的代码中,您只检查了一些选项,其中许多选项实际上并没有出售整根杆。

请注意,此解决方案远非解决此问题的最有效解决方案。它不考虑重叠的子问题,这在您提供的链接中得到解决。

【讨论】:

    【解决方案2】:

    您的递归调用在下降/上升期间丢失了信息。

    在您的返回调用期间,看到它在数组中向后工作,它所要做的就是返回最大可能值并忽略剩余的卡盘。

    假设这个极端的例子是n=2;p=[100,1];。理想情况下,答案是 200。

    第一次调用时,返回值为return max(1,cutRod(2,2-1));。 第一次调用的第二个参数cutRod(2,2-1) 忽略了杆的第二个卡盘,并在递归调用中开始检查杆的第一个卡盘。

    第二层调用给max(100,cutRod(2,1-1));

    第三个电话,i=0,所以它是cutRod(2,0) = 0

    检查递归调用的级别,我们只取这对值的最大值:

    level 3 = 0 //0 comes from cutRod(2,1-1)
    level 2 = max(100,0) //100 comes from cutRod(2,2-1): 0 comes from cutRod(2,1-1)
    level 1 = max(1,100) //1 comes from p[2-1]: 100 comes from max(100,0)
    

    所以 100 最终是最大值,而不是回电时的 200

    return max(price[i-1] + cutRod(price,n-(i+1),i), cutRod(price,n,i-1));
    

    我不推荐这种多次递归调用的方式来解决这个动态编程问题。相反,这是在中找到的示例 算法简介, 第三版 Cormen, Leiserson, Rivest, Stein pg.363

    #include <limits.h>
    //p is the price array
    //n is the initial size of the array or 'rod'
    int cutRod(int p[],int n){
      if(n == 0){
        return 0;
      }
      int q = INT_MIN;
      for(int i = 1; i<=n; i++){
        q = max(q,p[i-1]+cutRod(p,n-i));
      }
      return q;
    }
    

    没有 for 循环的递归解决方案 *需要分析

    //p is the price array, n is the size of the array/rod, i is index initial called with 0
    int cutRod(int p[],int n,int i){
      if(n<=0 || i>=n){
        return 0;
      }
      return max(p[i]+cutRod(p,n-(i+1),0),cutRod(p,n,i+1));
    }
    

    【讨论】:

    • 是的,我知道这是一个 DP 问题。但首先我想使用递归解决,然后将这种方法用于 DP。但是我在递归本身中陷入了困境。我对正在使用的 FOR 循环有疑问。为什么我们不能像背包问题一样解决它?
    • @Rahul 在背包问题中,变量表现为离散对象。一旦你把东西放进袋子里,你就不能把它放回去,因为它已经在袋子里了,所以在递归迭代期间你有“独特的”子问题。使用 cutRod,移动价格数组的索引不起作用。对于棒的每个子迭代,您必须从 0 开始,否则信息会丢失。有关递归解决方案,请参阅我的编辑。
    【解决方案3】:

    #Python 解决方案 它会给出 TLE 错误,所以请确保使用记忆的解决方案。

    class Solution:
        def __init__(self):
            self.ans=0
        def cutRod(self, price, n):
            l=[]
            for i in range(1,n+1):
                l.append(i)
            rod_l=n
            self.solve(l,price,n,rod_l)
            return self.ans
        
        def solve(self,l,price,n,rod_l):
            if n==0 or rod_l<1:
                return 0
            if l[n-1]<=rod_l:
                self.ans=max(self.solve(l,price,n-1,rod_l),price[n-1]+self.solve(l,price,n,rod_l-l[n-1]))
                return self.ans
            else:
                self.ans=self.solve(l,price,n-1,rod_l)
                return self.ans
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 1970-01-01
      相关资源
      最近更新 更多