给定长度任意长度的钢条的价值,求解如何切割,使给定长度为n的钢条的价值最大。
对于长度为n的钢条,考虑子问题,我们遍历1~n的第一个切割的位置j,即得到长度为j和n-j的两段钢条,第一段不再切割,仅对第二段继续切割,递归求解,于是就得到了一个递归解法。这里是C语言实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define min -999999
#define maxsize 9999
int r[maxsize];//长度为n钢条最大价值
int cut_pop_recursive(int n, int p[]) {//暴力递归求解
int i, j, k, max = min;
if (n <= 1)return p[n];
for (i = 1; i <= n; i++) {
max = max > p[i] + cut_pop_recursive(n - i, p) ? max : p[i] + cut_pop_recursive(n - i, p);
}
return max;
}
但是可以看出时间复杂度极高为2^n。
不难发现,在求解过程中,重复求解了多次同样的子问题,因此不妨考虑将子问题的解存起来。
于是得到第二个解法
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define min -999999
#define maxsize 9999
int r[maxsize];//长度为n钢条最大价值
void Memorized_cut_pop_init(int n) {//初始化
int i;
for (i = 0; i <= n; i++) {
r[i] = min;
}
r[0] = 0;
}
int Memorized_cut_pop_recursive(int n, int p[]) {//自上而下
int i, max = min;
if (r[n] == min) {
for (i = 1; i <= n; i++) {
max = max > p[i] + Memorized_cut_pop_recursive(n - i, p) ? max : p[i] + Memorized_cut_pop_recursive(n - i, p);
}
r[n] = max;
}
return r[n];
}
这是一种自上而下的求解方法,时间复杂度为o(n^2)
下面是一种复杂度常系数更小的自下而上的解法
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define min -999999
#define maxsize 9999
int r[maxsize];//长度为n钢条最大价值
void Memorized_cut_pop_init(int n,int p[]){
int i;
for(i=0;i<=n;i++){
r[i]=min;
}
r[0]=0;
}
void Memorized_cut_pop(int n,int p[]){
int i,j;
for(i=1;i<n;i++){
for(j=1;j<=n;j++){
r[i]=r[i]>p[i]+r[i-j]?r[i]:p[i]+r[i-j];
}
}
}
ps:后两种解法调用前都需要初始化