问题描述
有一个长度为n的钢条需要切割成短钢条出售,长度不同的钢条售价也不同,如下:
长度i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
价格p[i] | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 |
那么怎么切割才能获得最大利益呢
暴力解决思路
只要列出每种切割方案,然后比较一下哪种切割方案利润最大不就可以了吗(手动滑稽
假设有一个长度为4的钢条,那么有一下四中切割方案
编号 | 切割方案 | 利润 |
---|---|---|
① | ■■■■ | 9 |
② | ■■■,■ | 9 |
③ | ■■,■■ | 10 |
④ | ■■,■,■ | 6 |
⑤ | ■,■,■,■ | 4 |
发现当钢条长度为4时,切割成两个长度为2的短钢条利润最大。而且当切割钢条时,若切割完成后的钢条长度小于等于1的话,则可以把这个钢条看成规模更小的相同问题,用同样的方法先求出这个短钢条的最大利润,然后比较所有组合的利润,构成原问题的解。
钢条切割问题满足最优子结构的性质:问题的最优解由相关问题的最优解组合而成,而这些子问题可以独立求解。
通过递归的求解方式可以写出简单的求解程序:从钢条的左边切割下一段长度为i的短钢条,然后右边为长度就为n-i的短钢条,然后对右边继续递归求解,知道右边的长度为0,则返回零。
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
// 不同长度钢条的价格
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int cutROd(int p[], int n){
int i, q;
if(n == 0)
return 0;
q = -INF;
for(i = 1; i <= n; i++){
q = max(q, p[i] + cutROd(p, n - i));
}
return q;
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", cutROd(p, n));
return 0;
}
指数爆炸
图样图森破啊,这个程序的复杂度是2^n,所以输入大一点的数就会指数爆炸了,等半天结果才会出来,所以这样写太native了
更高效的方法
改进上面的程序
上面的程序之所以低效,因为有很多重复的计算啊,比如说计算长度为4的钢条,便有多次计算了长度为2和3的最优解,更不要说在大一点的数要重复计算多少次了。但是,如果能避免这些重复计算的,算法的效率就会非常高了,只要在第一次计算中吧结果记录下来,下次需要用到的时候直接调用就可以了。
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int memoizedCutRodAux(int p[], int n, int r[]){
int q;
if(r[n] >= 0)
return r[n];
if(n == 0)
q = 0;
else{
q = -INF;
int i;
for(i = 1; i <= n; i++)
q = max(q, p[i] + memoizedCutRodAux(p, n-i, r)) ;
}
r[n] = q;
return q;
}
int memoizedCutRod(int p[], int n){
int r[11], i;
for(i = 0; i < 11; i++)
r[i] = -INF;
return memoizedCutRodAux(p, n, r);
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", memoizedCutRod(p, n));
return 0;
}
另一种解法
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define INF 0x7fffff;
int p[11] = {
0,1,5,8,9,10,17,17,20,24,30
};
int buttomUpCutRod(int p[], int n){
int r[n+1];
r[0] = 0;
int i, j;
for(i = 1; i <= n; i++){
int q = -INF;
for(j = 1; j <= i; j++)
q = max(q, p[j] + r[i - j]);
r[i] = q;
}
return r[n];
}
int main(){
int n;
scanf("%d", &n);
printf("%d\n", buttomUpCutRod(p, n));
return 0;
}