青训营X豆包MarsCode 技术训练营题解 | 豆包MarsCode AI 刷题

69 阅读3分钟

青训营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 来记录在不同预算下的最大载货量。

算法步骤

  1. 二进制优化

    • 对于每种货船 (m[i], v[i], w[i]),将其数量 m[i] 拆分成多个独立的物品。
    • 使用二进制分解的方法,将 m[i] 拆分成 1, 2, 4, ..., 2^k 的形式,直到剩余的数量小于下一个2的幂。
    • 将每个拆分后的物品加入到 items 列表中。
  2. 动态规划求解

    • 初始化一个长度为 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]