切割钢条问题
给出每种长度钢条对应的价格,对于长为n的钢条,怎样切割使得总利益最大。
找到一个分割点,左边不再切割,右边递归求解。
自顶向下,带备忘:
R[n]保存对应解,避免重复求解
#include <stdio.h>
#include <iostream>
using namespace std;
int p[] = {0,1,5,8,9,10,17,17,20,24,30};
int cut_rod(int n,int *r) {
int q = 0;
if (r[n] >= 0)
return r[n];
if (n ==0)
q = 0;
else {
q = -1000000;
for (int i = 1;i <= n;i++) {
int m = p[i]+ cut_rod(n-i,r);
q = (m > q)?m:q;
}
}
r[n] = q;
return q;
}
int main () {
int n = 0;
cin >> n;
int r[10000];
for (int i = 0;i <= n;i++) {
r[i] = -10000;
}
int max = cut_rod (n,r);
printf ("%d\n",max);
return 0;
}
自底向上,重构解:
长度为1的最好切割方案已经找到,随着长度的增大,它的子问题即较短长度的已经解决,直接使用,不递归。
#include<stdio.h>
#include <iostream>
using namespace std;
int p[] = {0,1,5,8,9,10,17,17,20,24,30};
//钢条长度对应的价格
int * bottom_up (int n,int c) {
static int s[10000];
//保留切割点
int r[10000];//每长度对应的最大值
r[0] = 0;
for (int i = 1;i <= n;i++) {
int q = -10000;
for (int j = 1;j <= i;j++) {
int m = p[j]+r[i-j];
if (r[i-j] != 0)
m -= c;
//当后半段不为0时,计入成本
if (m > q) {
q = m;
s[i] = j;
}
}
r[i] = q;
}
cout << r[n] << endl;
return s;
}
int main () {
int n = 0; //钢条长度
int c = 0; //切割成本
cin >> n >> c;
int *p;
p = bottom_up (n,c);
for (int i = n;i > 0;i -= *(p+i)) {
cout << *(p+i) << " ";
//依次输出切割步骤
}
cout << endl;
return 0;
}