做题笔记:租用货船的最大载货量问题
题目分析
-
问题背景:
- 有 QQ 种类型的货船,每种货船的数量、租赁成本、载货量是已知的。
- 目标是在有限预算 VV 元内,选择一种或多种货船组合,使总载货量最大。
-
输入参数:
-
QQ:货船种类数量。
-
VV:总预算。
-
shipsships:一个包含 QQ 个元组的列表,每个元组表示某种货船的属性 [m[i],v[i],w[i]][m[i], v[i], w[i]]:
- m[i]m[i]:第 ii 种货船的最大可租数量。
- v[i]v[i]:第 ii 种货船每艘的租赁成本。
- w[i]w[i]:第 ii 种货船每艘的最大载货量。
-
-
目标:
- 选择货船,使得总预算 ≤V\leq V,且总载货量尽可能大。
-
约束条件:
- 每种货船的租用数量不能超过其最大数量 m[i]m[i]。
- 总租赁费用不能超过预算。
解题思路
这是一个多重背包问题的变种,解题时可参考动态规划方法解决背包问题:
-
多重背包问题简介:
- 每种物品有多件(如货船数量 m[i]m[i])。
- 选择物品时需考虑其费用限制(如租赁成本 v[i]v[i])。
- 每种物品的价值为 w[i]w[i],目标是最大化价值。
-
动态规划核心思想:
- 定义 dp[j]dp[j]:表示在预算 jj 元时的最大总载货量。
- 每种货船可以租用 00 至 m[i]m[i] 艘。对于每种租用方案,更新动态规划数组。
-
状态转移方程:
-
遍历货船,设当前货船的属性为 [m,v,w][m, v, w],对于预算从 VV 到 vv 进行逆序更新:
- 尝试租用 kk 艘货船(1≤k≤m1 \leq k \leq m 且 j≥k⋅vj \geq k \cdot v): dp[j]=max(dp[j],dp[j−k⋅v]+k⋅w)dp[j] = \max(dp[j], dp[j - k \cdot v] + k \cdot w)
-
-
优化:
- 遍历时,需从大到小更新 dpdp,避免重复利用当前船只。
- 对于多重背包问题的优化,可以尝试二进制拆分或更高效的处理方法。
代码思路分析
以下是代码的逐步解析:
-
初始化动态规划数组:
dp = [0] * (V + 1)- 创建大小为 V+1V+1 的数组 dpdp,初始值为 00。
- dp[i]dp[i] 表示预算为 ii 时的最大载货量。
-
遍历每种货船的属性:
for m, v, w in ships:- 遍历货船列表 shipsships,获取每种货船的数量 mm、租赁成本 vv 和最大载货量 ww。
-
多重背包核心处理:
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)- 从总预算 VV 开始,逐步尝试减少预算 jj。
- 尝试租用 kk 艘货船,若 k⋅v≤jk \cdot v \leq j,更新最大载货量 dp[j]dp[j]。
-
返回结果:
return dp[V]- 最终 dp[V]dp[V] 为给定预算下的最大载货量。
代码优化建议
-
多重背包的优化:
- 使用二进制拆分法将 m[i]m[i] 拆解为若干组物品,降低时间复杂度。
- 或者在更新 dpdp 时,直接以 m[i]m[i] 为上限优化内部循环。
-
减少循环次数:
- 若 m[i]⋅v[i]>Vm[i] \cdot v[i] > V,则直接视为无限背包问题,简化计算。
总结
-
复杂度分析:
- 时间复杂度:O(Q⋅V⋅max(m[i]))O(Q \cdot V \cdot \text{max}(m[i]))。
- 空间复杂度:O(V)O(V)。
-
应用场景:
- 该问题是一类多重背包问题,可推广到资源分配、容量规划等实际问题中。
-
扩展思考:
- 若需求增加额外约束条件(如货船必须满足某种特殊配置),可通过增加状态变量解决。