一、题目解析
这道题目来自豆包MarsCode AI 刷题平台,属于经典的多重背包问题,考察我们如何在预算限制下选择物品以实现收益最大化。题目背景是一个货船租赁问题:
- 有 Q 种货船,每种货船的数量、租赁价格和最大载货量都已知;
- 给定总预算 V,需要选择租赁哪些货船,以使总载货量最大。
从题目可以看出,这是一个组合优化问题,需要考虑预算、货船数量和收益之间的平衡。不同于普通的01背包问题,这里每种货船的数量有限,因此需要动态规划来处理这种约束条件。
二、思路分析
-
背包问题本质: 这道题可以抽象成一个背包问题,其中:
- 背包容量:可用预算 V;
- 物品重量:货船的租赁价格;
- 物品价值:货船的最大载货量;
- 每种货船的数量:物品数量的约束。
本题属于多重背包问题,即每种物品(货船)的数量有限,需要在这个限制下选择最优组合。
-
动态规划思想: 我们使用动态规划来解决问题,定义 dp[j] 为在预算不超过 j 时,货船最大载货量的状态。主要步骤如下:
- 初始化:将 dp 数组初始化为全零,因为预算为零时,最大载货量显然为 0。
- 状态转移:对于每种货船,根据其数量,逐步更新当前预算下的最优解。
-
优化策略:
- 展开多重背包:对于每种货船,枚举可以选择的数量 k,将多重背包转化为多个01背包问题。
- 从后往前遍历:为了防止状态重复计算,需要对 dp 数组进行从后向前的更新。
三、举例分析
假设我们有以下示例:
-
输入:
- Q = 2, V = 10
- ships = [[2, 3, 2], [3, 2, 10]]
货船信息解释:
- 第一种货船:最多租 2 艘,每艘价格 3,载货量 2;
- 第二种货船:最多租 3 艘,每艘价格 2,载货量 10。
步骤:
-
初始化:
dp = [0] * (V + 1),表示在预算从 0 到 10 的每个状态下,最大载货量为 0。 -
处理第一种货船:
选择 k = 1, 2 艘货船,分别更新 dp 数组。- 租 1 艘:预算 3 时,载货量增加到 2。
- 租 2 艘:预算 6 时,载货量增加到 4。
此时的
dp数组为:dp = [0, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0]
-
处理第二种货船:
选择 k = 1, 2, 3 艘货船,分别更新 dp 数组。- 租 1 艘:预算 2 时,载货量增加到 10。
- 租 2 艘:预算 4 时,载货量增加到 20。
- 租 3 艘:预算 6 时,载货量增加到 30。
最终
dp数组更新为:dp = [0, 0, 10, 20, 20, 30, 32, 30, 40, 40, 50]
最后,我们可以看到在预算 10 时,最大载货量为 32。
四、代码实现
def solution(Q, V, ships):
# Please write your code here
dp = [0] * (V + 1)
for m, v, w in ships:
for j in range(V, v - 1, -1):
for k in range(1, m + 1):
if j >= k * v:
dp[j] = max(dp[j], dp[j - k * v] + k * w)
return dp[V]
五、总结
动态规划的本质是用状态转移方程描述问题,通过不断更新已知的最优解,最终找到全局最优解。这道题通过动态规划解决多重背包问题,考察了算法设计能力。关键在于灵活处理背包约束条件并构建合理的状态转移方程。