问题重现
在钢管切割的背景下,已经知道长度为1−n的钢管的价值,给定长度为n的钢管在切割若干次(也可以不切割)所带来的最小价值(最大价值)是?
问题分析
钢管切割问题大家都不陌生,这里就不具体举出某个例子了。具体的思路就是用dp[i]记录当总长度为i时的最小(最大)价值,即
dp[i] = min{p[i] + dp[i - j]}(j : 1 ➡ i)
代码
int bottm_up_cut_rod(int p[],int n){
int q;
for(int j = 1;j <= n;j++){
q = mx;
for(int i = 1;i <= j;i++){
q = min(q,p[i] + dp[j - i]);
}
dp[j] = q;
}
return dp[n];
}
注意
根据题目要求最大还是最小值,在以下两点会有区别
- 临时变量q的初始化,若求最大则初始化为-1,若求最小则初始化为一个超大的数
- dp数组的初始化,对于下标从1➡n的元素均按照上述方式初始化
换一种思路(钢管切割问题➡另类背包问题)
具体转化如下:
起始长度 ➡ 背包容量、物品种数
钢管每段长度 ➡ 物品重量
价值 ➡ 价值
同时是完全背包问题,因为每种长度的切割可以无限制,再同时,由于每段长度求和必等于原始长度,由此,这是一个要求装满的完全背包问题,贴上代码:
#include <iostream>
#include <cstdio>
#define maxn 1010
#define inf 9999999
using namespace std;
int dp[maxn],v[maxn],w[maxn];
int n;
void complete_pack(int vi,int wi){
for(int i = vi; i <= n; i++)//正序
dp[i] = min(dp[i],dp[i - vi] + wi);
}
void init(){
dp[0] = 0;
for(int i = 1;i < maxn;i++){
dp[i] = inf;
}
}
int main()
{
while(~scanf("%d",&n)){
init();
for(int i = 1;i <= n;i++){
v[i] = i;
scanf("%d", &w[i]);
}
for(int i = 1;i <= n;i++){
complete_pack(v[i],w[i]);
}
printf("%d\n", dp[n]);
}
return 0;
}