青训营X豆包MarsCode 技术训练AI刷题小S的货船租赁冒险 | 豆包MarsCode AI 刷题

16 阅读3分钟

解题思路

我们可以使用动态规划(Dynamic Programming, DP)来解决这个问题。动态规划非常适合解决这类“在给定约束下最大化/最小化某个值”的问题。

算法步骤

  1. 定义状态

    • 使用一个数组 dp,其中 dp[j] 表示在预算为 j 时能租用的货船的最大总载货量。
  2. 状态转移

    • 对于每种货船 (m, v, w),我们需要考虑在预算 j 内租用该货船的情况。
    • 由于每种货船有数量限制 m,我们需要遍历每种货船的所有可用数量。
    • 对于每个预算 j,我们需要更新 dp[j],考虑是否租用当前货船。
  3. 遍历顺序

    • 由于我们需要避免重复使用同一艘货船进行多次计算,内层循环应该从大到小遍历预算 j

代码

def solution(Q, V, ships):
    # 初始化 dp 数组,长度为 V+1,所有元素初始化为 0
    # dp[j] 表示在预算为 j 时能租用的货船的最大总载货量
    dp = [0] * (V + 1)
    
    # 遍历每种货船的信息 (m, v, w)
    for m, v, w in ships:
        # 对于当前货船,遍历其所有可用的数量 m
        for _ in range(m):
            # 从预算的最大值 V 开始,向前遍历到该货船的租赁成本 v(包含 v)
            # 注意要逆序遍历,以避免重复使用同一艘货船进行多次计算
            for j in range(V, v - 1, -1):
                # 更新 dp[j],表示在预算为 j 时能得到的最大载货量
                # 要么保持原来的值 dp[j],要么选择租用当前货船并加上剩余预算下的最大载货量 dp[j - v] + w
                dp[j] = max(dp[j], dp[j - v] + w)
    
    # 返回在预算 V 下的最大载货量
    return dp[V]

if __name__ == "__main__":
    #  You can add more test cases here
    ships = [[2, 3, 2], [3, 2, 10]]
    ships2 = [[30, 141, 47], [9, 258, 12], [81, 149, 13], [91, 236, 6], [27, 163, 74], [34, 13, 58], [61, 162, 1], [80, 238, 29], [36, 264, 28], [36, 250, 2], [70, 214, 31], [39, 116, 39], [83, 287, 4], [61, 269, 94], [23, 187, 46], [78, 33, 29], [46, 151, 2], [71, 249, 1], [67, 76, 85], [72, 239, 17], [61, 256, 49], [48, 216, 73], [39, 49, 74]]
    print(solution(2, 10, ships) == 32)
    print(solution(23, 400, ships2) == 1740)

优化思路

  1. 二进制优化

    • 通过判断 k & (k - 1) == 0 来确定 k 是否为2的幂次方。如果是,则 count 为 k;否则,count 为1。
    • 这样可以减少内层循环的次数,因为每次只处理2的幂次方的数量。
  2. 减少内层循环的次数

    • 内层循环从 V 开始,向前遍历到 v * count - 1,这样可以避免不必要的计算。