【题解】小S的货船租赁冒险 | 豆包MarsCode AI刷题

48 阅读4分钟

问题描述

小S在码头租用货船,有 QQQ 种不同类型的货船可供选择。每种货船有固定的数量 m[i]m[i]m[i]、租赁成本 v[i]v[i]v[i] 和最大载货量 w[i]w[i]w[i]。小S希望在预算 VVV 元内,租用能够承载最大总货物的货船组合。每种货船的具体信息包括数量、租赁价格和载货量。请帮助小S计算在给定预算下,她能租用的货船的最大总载货量是多少。

输入描述

  • Q: 货船的种类数量。
  • V: 可用的总预算(单位:元)。
  • ships: 一个列表,其中每个元素是一个元组 [m[i],v[i],w[i]][m[i], v[i], w[i]][m[i],v[i],w[i]],分别表示第 iii 种货船的数量、租赁价格和每艘货船的最大载货量。

输出描述

返回在预算 VVV 内能够承载的最大总货物量。

问题分析

这是一个典型的多重背包问题。我们需要在预算 VVV 的限制下,从 QQQ 类货船中选择,尽可能使总载货量最大化。每种货船有数量限制、租赁成本和载货量。

关键点

  1. 多重背包问题:每种货船有一定数量限制,可以选择多个同类型的货船,但不能超过该数量。
  2. 最大化载货量:在预算限制下,选择货船组合使得总载货量最大。
  3. 优化方法:使用二进制拆分将多重背包问题转化为0-1背包问题,降低时间复杂度。

约束条件

  • 货船种类数量 Q 可能较大。
  • 每种货船的数量 m[i] 可能较大,直接处理会导致时间复杂度过高。
  • 需要在预算 V 内选择货船组合。

解法实现

思路

  1. 动态规划(DP) :使用一维DP数组 dp[v] 表示在预算为 vvv 元时能够达到的最大载货量。
  2. 二进制拆分:将每种货船的数量 m[i]m[i]m[i] 拆分为多个子问题,每个子问题对应 2k2^k2k 个货船,直到总数达到 m[i]m[i]m[i]。
  3. 状态转移:对于每个拆分后的子货船,遍历预算,从高到低更新 dp[v]
def solution(Q, V, ships):
    dp = [0] * (V + 1)
    for ship_index in range(Q):
        m, cost, capacity = ships[ship_index]
        # 二进制拆分,将 m 个物品拆分成 log(m) 个物品
        k = 1
        while m > 0:
            count = min(k, m)  # 本次选取的数量
            m -= count
            total_cost = count * cost
            total_capacity = count * capacity
           #从高到低遍历,防止重复计算
            for v in range(V, total_cost - 1, -1):
                if dp[v - total_cost] + total_capacity > dp[v]:
                    dp[v] = dp[v - total_cost] + total_capacity
            k <<= 1  # k *= 2

    return dp[V]

核心逻辑

  1. 动态规划数组 dp 初始化

    • dp[v] 表示在预算为 v 元时,能够达到的最大总载货量。
    • 初始时,所有 dp[v] 都设为 0,因为未选择任何货船时载货量为 0
  2. 二进制拆分优化

    • 对于每种货船,数量 m[i] 可能较大。为了高效处理,可以将其拆分为若干个数量为 2^k 的子问题。
    • 例如,m = 5 可以拆分为 1, 2, 2
    • 这种方法将时间复杂度从 O(m)O(m)O(m) 降低到 O(log⁡m)O(\log m)O(logm)。
  3. 动态规划状态转移

    • 对于每一个拆分后的子货船,遍历预算 v 从高到低,尝试更新 dp[v]
    • 更新规则为:dp[v] = max(dp[v], dp[v - total_cost] + total_capacity),其中 total_costtotal_capacity 分别是当前拆分子货船的总租赁成本和总载货量。
  4. 最终结果

    • 遍历完所有货船后,dp[V] 即为在预算 V 内能够达到的最大总载货量。

时间复杂度

  • 拆分阶段:对于每种货船,最多拆分为 O(log⁡m[i])O(\log m[i])O(logm[i]) 个子问题。
  • 动态规划阶段:每个子问题需要遍历预算 V,时间复杂度为 O(V)O(V)O(V)。
  • 总时间复杂度:O(Q⋅log⁡m⋅V)O(Q \cdot \log m \cdot V)O(Q⋅logm⋅V),其中 m 是每种货船的最大数量。

空间复杂度

  • 主要由动态规划数组 dp 决定,空间复杂度为 O(V)O(V)O(V)。

结论

通过将多重背包问题转化为多个0-1背包问题,并利用二进制拆分优化,能够有效地在较低的时间复杂度下求解。在预算有限的情况下,选择最优的货船组合以最大化载货量是一种常见的资源分配问题,适用于物流、运输等多个领域。