杆切割 - 动态规划

时间:2016-07-22 09:14:21

标签: algorithm dynamic-programming

问题陈述

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

考虑n=4时的情况。图中显示了切割长度为4英寸的杆的所有方法,包括完全没有切割的方式。我们看到将4英寸的杆切成两个2英寸的杆可以产生P2+P2=5+5=10的收益,这是最佳的。

enter image description here

以下代码是一种自下而上的方法,用于构建切杆解决方案。

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])

3 个答案:

答案 0 :(得分: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]);

答案 1 :(得分:0)

如果我正确理解了问题,则无法从实现中删除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中的信息。

答案 2 :(得分:0)

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

#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;
}