1、问题描述
对于不同长度的钢条,其价格各不相同,现给定一个钢条的价格表,以及长度为n的钢条,求如何切割这个长度为n的钢条,使得价值最大。
2、样例分析
假如现在给定一价格表如下:
1 2 3 4 5 6 7 8 9 10
1 5 8 9 10 17 17 20 24 30
现有一个长度为4的钢条,如何切割才能使得价值最大?
总共有三种切割方案,分别为:
1、0+4,价值为9.
2、1+3,价值为1+8=9.
3、2+2,价值为5+5=10.
所以,切割方案为2+2时,所获得的价值最大。
3、问题解析
对于长度为n的钢条,假设最佳的切割点为:k,(1<k<=n).这时,将原问题转化成了两个规模更小的子问题,子问题的规模分别为:k和n-k。原问题的最优解切割方案依赖子问题的最优切割方案。然后依次找出子问题,子子问题的最优切割方案。
为了使问题变得更加简化,我们每次从钢条的左端切去长度为i的钢条,然后对剩下的长度为n-i的钢条继续进行切割。此时,对切下的长度为i的钢条不再进行切割,只对n-i进行切割。
在此,又有两种思路:
1)自顶向下的递归方案。每次在钢条的左侧切下长度为k的钢条,然后对右侧长度为n-k的钢条继续进行递归,找出最优的切割方案。这种方法存在一个问题,就是会反复求解相同的子问题。这时,需要将已经计算出的子问题结果进行保存,当下次需要求解相同子问题时,不需要重新进行计算。
2)自底向上的切割方案。依次计算长度为1,2,3,...,n的最优切割方案,第n次的最优切割方案,依赖于前n-1次的最优切割方案。
4、算法实现
对于以上的两种思路,分别将其进行了实现。其中函数CutSteel1使用自顶向下的递归方案来实现钢条的最优切割,而函数CutSteel2使用自底向上的钢条切割方案。两种方案的时间复杂度都为O(n2).
<span style="font-size:18px;">/**
钢条切割问题
给出一个价格表,如下:
1 2 3 4 5 6 7 8 910 (m = 10)
1 5 8 9 10 17 17 20 24 30
现有长度为n的钢条,求如何切割才能使得价值最大。
**/
#include <stdio.h>
#include <string.h>
int price[1002];
//up --> bottom
int cutSteel1(int n, int r[], int s[]) //return the maxValue
{
int i, tmp, hel, ss;
if(r[n] >= 0)
return r[n];
if(0 == n)
{
tmp = 0;
}
else
{
for(i=1; i<=n; i++)
{
if(1 == i){
tmp = price[i]+cutSteel1(n-i, r, s);
ss = i;
}
else{
hel = price[i] + cutSteel1(n-i, r, s);
if(tmp < hel)
{
tmp = hel;
ss = i;
}
}
}
s[n] = ss;
// r[n] = tmp;
}
r[n] = tmp;
return r[n];
}
//bottom --> up
int cutSteel2(int n, int r[], int s[])
{
int i, j, tmp, hel, ss;
r[0] = 0;
s[1] = 1;
for(i=1; i<=n; i++)
{
tmp = price[1]+r[i-1];
ss = 1;
for(j=2; j<=i; j++)
{
hel = price[j]+r[i-j];
if(tmp < hel)
{
tmp = hel;
ss = j;
}
}
s[i] = ss;
r[i] = tmp;
}
return r[n];
}
void print(int n, int s[])
{
int i;
printf("切割方案: ");
for(i=n; i>0; i=i-s[i])
printf("%d\t", s[i]);
printf("\n\n");
}
int main()
{
freopen("in.test", "r", stdin);
int m, n;
int i, maxValue;
int r[1002], s[1002];
// input the price table
memset(price, 0, sizeof(price));
scanf("%d", &m);
for(i=1; i<=m; i++)
scanf("%d",&price[i]);
//input the length n
while(scanf("%d", &n)==1)
{
memset(r, 0xffffffff, sizeof(r));
memset(s,0,sizeof(s));
maxValue = cutSteel1(n, r, s);
//maxValue = cutSteel2(n, r, s);
printf("n=%d, maxValue = %d\n", n, maxValue);
print(n, s);
}
return 0;
}</span>