问题描述:
给定一根长度为
l
l
l 的钢条
(
l
<
=
10000
)
(l<=10000)
(l<=10000),以及一张价格表,请计算这根钢条能卖出的最大总收益。
价格表表示为
(
l
i
,
p
i
)
(l_i, p_i)
(li,pi),
1
<
=
i
<
=
k
1<=i<=k
1<=i<=k。
不在价格表中的钢条可卖出价格为
0
0
0。
思路:
根据动态规划的思想,我们可以构建一个数组 d p dp dp,其中 d p [ n ] dp[n] dp[n] 代表了当总钢条长度为 n n n 时所能卖出的最大价值,则递推式显然如下:
d
p
[
n
]
=
max
1
<
=
i
<
=
k
(
p
i
+
d
p
[
n
−
l
i
]
)
w
h
e
n
n
>
=
l
i
dp[n] = \max_{1<=i<=k}(p_i + dp[n-l_i]) \quad when \quad n>=l_i
dp[n]=1<=i<=kmax(pi+dp[n−li])whenn>=li
d
p
[
n
]
=
0
w
h
e
n
n
<
l
i
.
.
.
k
dp[n] = 0 \quad when \quad n<l_{i...k}
dp[n]=0whenn<li...k
而初始化时,只需要将 d p [ 0 , . . . , m i n L e n g t h ] dp[0,\quad ...,\quad minLength] dp[0,...,minLength]设置为 0 0 0即可。
源代码:
//
// main.cpp
// SteelCutting
//
// Created by 胡昱 on 2021/11/11.
//
#include <iostream>
#include <vector>
using namespace std;
class Steel{
public:
int length;
int value;
Steel(int l, int v) {
length = l;
value = v;
}
};
int main() {
// 共m个问题
int m;
cin >> m;
while((m--) > 0) {
// 输入总钢条长度和价格表中不同价格的钢条的数量
int l = 10000, c = 100;
cin >> l >> c;
// 构建动态规划数组
// dp[i]代表了当总钢条长度为i时的最大产出价值
int* dp = new int[l + 1];
// 输入钢条长度价格表(如果长度超出了总钢条长度则不用输入)
vector<Steel> steel;
int length, value, minLength = 2147483647;
for(int i = 0; i < c; ++i) {
cin >> length >> value;
if(length <= l) {
steel.push_back(Steel(length, value));
minLength = min(minLength, length);
}
}
// 如果不能切出任何钢条则直接输出0
if(steel.empty()) {
cout << 0 << endl;
continue;
}
// 进一步初始化动态规划数组
for(int i = 0; i < minLength; ++i) {
dp[i] = 0;
}
// 开始自底向上动态规划
for(int li = minLength; li < l + 1; ++li) {
int tempValue = 0;
for(int i = 0; i < steel.size(); ++i) {
if(steel[i].length <= li) {
tempValue = max(tempValue, steel[i].value + dp[li - steel[i].length]);
}
}
dp[li] = tempValue;
}
cout << dp[l] << endl;
delete [] dp;
}
}