题目
有个藏宝架有n层,每层的宝物数量不一,每个宝物都有其价值,现在要求拿出m个宝物,并且需要遵守规则:
- 每次只能拿选定层的两端的宝物
- 要拿出的m个宝物的总价值是各种方案里最大的
输入:(第一行是 n 和 m,后面每一行是各层的数据)
n m
下面每行代表每层,且第一个数是这层宝物的数量k,后面的则是k个宝物的价值
4 1 2 4 5
5 1 2 4 5 5
样例:
2 3
2 3 2
4 1 4 1 5
输出:5+3+2=10
(注意,每一层中,给出的宝物的价值不是排好序的)
方法一 多重背包
比较经典的解法是用多重背包。如果不了解这个算法,可以先康康:https://www.kancloud.cn/kancloud/pack/70127
processValues(int[] values) 输入为每一层的k个宝物的价值,返回的是从这一层中,取0个 - k 个宝物时,可获取的最大价值。
主函数中,先读数据,然后调用processValues() 处理每一层的值,存到 goods 矩阵中,最后进行动态规划。
dp[ i ][ j ] 表示从 0 - i层,取了j 个货物时获取的价值。
状态转移方程为:
(假设第 i 层的货物数量为 length;注意下面方程中的 k 只是一个循环变量)
dp[i][j] = max( {
1 <= k <= min(length, j) | dp[i - 1][j - k] + goods[i][k] } )
这里的 k 其实表示的是在 i 层取了 k 件物品,然后在 (i - 1)层取 ( j - k )件,加起来就是 j 件。
时间复杂度是 O(nmk)
public class bao_wu_7_27_dp {
// 对每层的货物,取 0 到 k 个时的最大价值
// values 是某层货物的价值
// 比如,temp[0] 为取0个时的最大价值,temp[2]为取2个时的最大价值
public static int[] processValues(int[] values) {
int[] temp = new int[values.length + 1];
temp[0] = 0;
int i = 0;
int j = values.length - 1;
int cur = 1;
while(cur < temp.length) {
if (values[i] > values[j]) {
temp[cur] = values[i] + temp[cur - 1]