青训营X豆包MarsCode 技术训练营——小S的船货租赁风险 | 豆包MarsCode AI 刷题
问题描述
小S在码头租用货船,有 Q 种不同类型的货船可供选择。每种货船有固定的数量 m[i]、租赁成本 v[i] 和最大载货量 w[i]。小S希望在预算 V 元内,租用能够承载最大总货物的货船组合。每种货船的具体信息包括数量、租赁价格和载货量。小S需要你帮忙计算在给定预算下,她能租用的货船的最大总载货量是多少。
Q: 货船的种类数量。V: 李华可用的总预算(单位:元)。ships: 一个列表,其中每个元素是一个元组[m[i], v[i], w[i]],分别表示第i种货船的数量、租赁价格和每艘货船的最大载货量。
测试样例
样例1:
输入:
Q = 2,V = 10,ships = [[2, 3, 2], [3, 2, 10]]
输出:32
样例2:
输入:
Q = 3,V = 50,ships = [[5, 10, 20], [2, 20, 30], [3, 15, 25]]
输出:100
样例3:
输入:
Q = 1,V = 100,ships = [[10, 5, 50]]
输出:500
样例4:
输入:
Q = 4,V = 100,ships = [[1, 100, 200], [2, 50, 100], [3, 33, 66], [4, 25, 50]]
输出:200
样例5:
输入:
Q = 2,V = 300,ships = [[100, 1, 1], [50, 5, 10]]
输出:550
代码思路
多重背包问题的二进制优化方法。
问题理解
需要在给定的预算 V 内,选择不同类型的货船,使得总载货量最大化。每种货船有数量限制、租赁成本和载货量。
数据结构选择
- 二进制优化:将每种货船的数量
m[i]拆分成多个独立的物品,每个物品的重量和价值是原物品的倍数。这样可以避免直接处理数量限制,转化为0-1背包问题。 - 动态规划数组:使用一个一维数组
dp来记录在不同预算下的最大载货量。
算法步骤
-
二进制优化:
- 对于每种货船
(m[i], v[i], w[i]),将其数量m[i]拆分成多个独立的物品。 - 使用二进制分解的方法,将
m[i]拆分成1, 2, 4, ..., 2^k的形式,直到剩余的数量小于下一个2的幂。 - 将每个拆分后的物品加入到
items列表中。
- 对于每种货船
-
动态规划求解:
- 初始化一个长度为
V + 1的数组dp,表示在不同预算下的最大载货量。 - 对于每个物品
(v, w),从后向前遍历预算j,更新dp[j]为max(dp[j], dp[j - v] + w)。
- 初始化一个长度为
总结
- 二进制优化:将多重背包问题转化为0-1背包问题,减少了物品的数量,提高了效率。
- 动态规划:通过动态规划数组
dp记录在不同预算下的最大载货量,最终返回dp[V]即为在预算V下的最大载货量。
题解
def solution(Q, V, ships):
# 二进制优化
items = []
for m, v, w in ships:
c = 1
while m > c:
m -= c
items.append([v * c, w * c])
c *= 2
items.append([v * m, w * m])
# 动态规划数组
dp = [0] * (V + 1)
# 动态规划求解
for item in items:
for j in range(V, item[0] - 1, -1):
dp[j] = max(dp[j], dp[j - item[0]] + item[1])
return dp[V]