问题陈述
切杆问题如下。给定n
英寸长度的杆和Pi
的价格表i = 1, 2, 3,....n
,确定通过切割杆和销售件获得的最大收益Rn
。请注意,如果长度为Pn
的杆的价格n
足够大,则最佳解决方案可能根本不需要切割。
考虑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])
?
答案 0 :(得分:1)
您应该使用两个不同的数组r
和p
,因为它们的含义完全不同。值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;
}