【问题标题】:Rod Cutting - Dynamic Programming棒材切割 - 动态规划
【发布时间】:2016-07-22 09:14:21
【问题描述】:

问题陈述


截杆问题如下。给定长度为n 英寸的杆和i = 1, 2, 3,....n 的价格表Pi,确定通过切割杆并出售碎片可获得的最大收入Rn。请注意,如果长度为n 的杆的价格Pn 足够大,则最佳解决方案可能根本不需要切割。

考虑n=4的情况。图中显示了切割 4 英寸长杆的所有方法,包括完全不切割的方法。我们看到,将一根 4 英寸的棒切成两根 2 英寸的小块会产生收入P2+P2=5+5=10,这是最优的。

下面的代码是一种自下而上的方法来构建切割棒的解决方案。

for (i = 1; i<=n; i++)
{
   int q = INT_MIN;
   for (j = 0; j < i; j++)
       q= max(q, p[j] + r[i-j-1]);
   r[i] = q;
}
return val[n];

为什么我们需要一个辅助数组r[n+1]?难道仅仅使用数组p就不能解决问题吗?使用它是因为我们在切割杆长度 n 和 0 时无法访问 p[-1] 吗? 为什么我们在 p 没有更新为新值时使用q = max(q, p[j] + r[i-j-1])

【问题讨论】:

  • 请附上切杆问题的定义以避免误解。
  • 添加了一个例子。
  • 内循环中的-1 让我有点困惑。
  • 据我了解,p 是输入的一部分,不能被覆盖;内部循环的每次迭代都需要原始数据。
  • return val[n]; 没有任何意义——n 只是杆的长度,val 没有在其他任何地方提及。

标签: algorithm dynamic-programming


【解决方案1】:

您应该使用两个不同的数组rp,因为它们的含义完全不同。 p[i] 的值告诉您,长度为 i+1 的完整(未切割)板的成本是多少。 r[i] 的值告诉您,使用长度为 i+1(完整或切成小块)的棋盘可以赚取多少利润。这些值不一样。例如,在您的示例中,您有p[3] = 9,但有r[3] = 10,因为您可以将长度为4 的板切割成长度为2 的两个较小的部分。将两种不同的含义保存在不同的数组中总是一个好主意。 (除非你有非常严格的内存限制)

此外,在实践中,您可能不会出售长度为 100 的木板。但您可能想知道通过切割这种尺寸的木板可以获得的最佳利润。如果你只有一个数组,你将不得不扩大它。根据您的语言选择,这也可能涉及创建第二个数组并复制第一个数组。因此,简单地使用第二个数组会更容易。

请注意,这是可能的(如果n 小于数组p 的长度)。仅使用一个数组的简单解决方案是(使用单索引):

int p[]={0,1,5,8,9,10,17,17,20,24,30};
int n = 4;
for (int i = 1; i <= n; i++)
{
    for (int j = 1; j <= i/2; j++)
        p[i] = max(p[i], p[j] + p[i - j]);
}
printf("%d\n", p[n]);

【讨论】:

  • 进一步,j 只能迭代一半。
【解决方案2】:

如果我正确理解了这个问题,那么就不可能从实现中删除r。显然r 的语义是

r[i] = maximum profit attainabble by cutting a rod of length i
       into pieces of the lengths 1,...,n

它需要在内部循环中访问。内循环中的递归关系转化为

q = the more profitable choice between not cutting a rod of length j
    and cutting a rod of length j (in which case we take p[j] as
    profit plus the maximum attainable profit of cutting the remaining
    rod, which has length j-i)

这意味着r中的信息是评估所必需的。

【讨论】:

  • 我没有使用r就实现了它。但一直不明白为什么在前面的案例中使用了r
  • 请展示没有r的实现;如果它是正确的,那么信息一定是在某个地方。
  • 已将其添加为答案。
【解决方案3】:

在内循环中不使用辅助数组且只迭代一半的棒切割问题。

#include <stdio.h>
#include <limits.h>

int max(int a,int b)
{
    return a>b?a:b;
}

int cut_rod(int p[],int n)
{
    int q=0;
    int r[n+1];   // Auxiliary array for copying p and appending 0 at index 0
    int i,j;

    if(n<0)
        return 0;
    else
    {
        r[0]=0;
        for(i=0;i<n;i++)
            r[i+1]=p[i];
        for(i=1;i<=n+1;i++)
        {
            q=INT_MIN;
            for(j=0;j<=i/2;j++)
                q=max(q,r[j]+r[i-j-1]);
            r[i-1]=q;
        }
    }
    return r[n];
}

int main()
{
    int p[]={1,5,8,9,10,17,17,20,24,30};
    int n=sizeof(p)/sizeof(int);
    int val;

    val=cut_rod(p,n);
    printf("%d",val);

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    • 1970-01-01
    • 2014-05-20
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多