问题描述
小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
问题建模
1. 输入数据
• Q:货船种类数量。
• V:预算(元)。
• ships:一个包含所有货船信息的列表,其中每个元素为 [m[i], v[i], w[i]],分别表示第 i 种货船的数量、租赁价格和最大载货量。
2. 输出结果
目标是在预算不超过 V 元的条件下,选择货船的组合,使总载货量达到最大。
3. 约束条件
• 每种货船的租用数量不能超过其提供的总量 m[i]。
• 总费用不能超过预算 V。
4. 背包问题抽象
这是一个典型的多重背包问题,每种货船提供一定数量的物品,每个物品有重量(租赁成本)和价值(载货量)。求解如何在总重量受限的条件下,使价值最大化。
解题思路
我们用**动态规划(Dynamic Programming, DP)**来解决这个问题。
1. DP 状态定义
定义 dp[j] 为在预算为 j 元的情况下,能够承载的最大总货物量。
2. 转移方程
对于每种货船 [m[i], v[i], w[i]]:
• 如果选择租用 k 艘(其中 0 \leq k \leq m[i] ):
• 租用的费用为 k * v[i]。
• 增加的载货量为 k * w[i]。
• 更新状态:dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i]),前提是 j - k * v[i] >= 0。
3. 初始化
• dp[0] = 0,表示预算为 0 时总载货量为 0。
• 其余 dp[j] 初始化为 0。
4. 最终结果
最后的答案是 dp[V],即在预算 V 元时,能够承载的最大总货物量。
def max_cargo(Q, V, ships):
# 初始化 dp 数组,长度为预算 V+1
dp = [0] * (V + 1)
# 遍历每种货船类型
for m, v, w in ships:
# 多重背包处理
for j in range(V, -1, -1): # 从高到低遍历预算
for k in range(1, m + 1): # 租用 0 到 m 艘货船
if j >= k * v:
dp[j] = max(dp[j], dp[j - k * v] + k * w)
return dp[V]
# 测试样例
Q = 3
V = 10
ships = [
[3, 2, 4], # 3 艘货船,每艘价格 2 元,载货量 4
[2, 3, 5], # 2 艘货船,每艘价格 3 元,载货量 5
[1, 5, 6] # 1 艘货船,每艘价格 5 元,载货量 6
]
print(max_cargo(Q, V, ships)) # 输出:14
示例讲解
输入数据
• Q = 3:货船种类数量为 3。
• V = 10:总预算为 10 元。
• ships:
• [3, 2, 4]:最多租 3 艘,每艘租赁价格 2 元,载货量 4。
• [2, 3, 5]:最多租 2 艘,每艘租赁价格 3 元,载货量 5。
• [1, 5, 6]:最多租 1 艘,每艘租赁价格 5 元,载货量 6。
解题过程
- 初始化 dp 数组:
dp = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]。
- 处理第一种货船 [3, 2, 4]:
• 租用 1 艘:dp[2] = max(dp[2], dp[0] + 4) = 4。
• 租用 2 艘:dp[4] = max(dp[4], dp[0] + 8) = 8。
• 租用 3 艘:dp[6] = max(dp[6], dp[0] + 12) = 12。
更新后:dp = [0, 0, 4, 0, 8, 0, 12, 0, 0, 0, 0]。
- 处理第二种货船 [2, 3, 5]:
• 租用 1 艘:dp[5] = max(dp[5], dp[2] + 5) = 9。
• 租用 2 艘:dp[8] = max(dp[8], dp[2] + 10) = 14。
更新后:dp = [0, 0, 4, 0, 8, 9, 12, 0, 14, 0, 0]。
- 处理第三种货船 [1, 5, 6]:
• 租用 1 艘:dp[10] = max(dp[10], dp[5] + 6) = 14。
最终:dp = [0, 0, 4, 0, 8, 9, 12, 0, 14, 0, 14]。
最优解
在预算 10 元下,最多可以承载的货物量为 14。
优化方向
1. 二进制优化
当货船数量 m[i] 很大时,可以用二进制分组优化,将复杂度从 O(Q \cdot V \cdot m[i]) 降低到 O(Q \cdot V \cdot \log m[i]) 。
2. 贪心与 DP 结合
当货船租赁价格 v[i] 和载货量 w[i] 成正比时,可以优先选择性价比高的货船,减少 DP 的计算范围。