题目解析:小S的货船租赁冒险 | 豆包MarsCode AI刷题

41 阅读3分钟

问题描述

小S在码头租用货船,面临一个优化问题:在有限的预算内,如何选择不同类型货船的组合以最大化总载货量。这个问题是一个典型的动态规划问题,可以通过构建一个二维数组来解决。

问题分析

首先,我们需要理解题目中的几个关键参数:

  • Q:货船的种类数量。
  • V:小S可用的总预算。
  • ships:一个列表,包含每种货船的数量m[i]、租赁价格v[i]和每艘货船的最大载货量w[i]

我们的目标是在不超过预算V的前提下,计算出能够租用的货船的最大总载货量。

思路解析

解决这个问题的关键在于使用动态规划(DP)的思想。我们可以定义一个二维数组dp,其中dp[i][j]表示在前i种货船中,预算为j时的最大载货量。通过遍历每一种货船和每一种预算,我们可以逐步构建这个数组。

算法详解与代码实现

  1. 初始化DP数组: 创建一个Q+1V+1列的二维数组dp,所有元素初始化为0。dp[0][j]表示没有货船时,预算为j的最大载货量,显然为0。

    def solution(Q, V, ships):
        dp = [[0] * (V + 1) for _ in range(Q + 1)]
    
  2. 遍历每一种货船: 对于每一种货船,我们需要考虑在不同预算下选择这种货船的不同数量。

    for i in range(1, Q + 1):
        m, v, w = ships[i - 1]
    
  3. 选择或不选择当前货船: 对于每一种预算,我们有两种选择:不选择当前货船,或者选择当前货船的不同数量。

    for j in range(V + 1):
        dp[i][j] = dp[i - 1][j]  # 不选择第 i 种货船
    
  4. 选择当前货船的不同数量: 我们需要计算在当前预算下,选择不同数量的当前货船能够得到的最大载货量。

    for k in range(1, min(m, j // v) + 1):
        if j >= k * v:
            dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v] + k * w)
    
  5. 返回结果: 最终,dp[Q][V]将包含在所有货船和预算V下的最大载货量。

    return dp[Q][V]
    
  6. 测试样例: 我们可以通过几个测试样例来验证算法的正确性。

    if __name__ == "__main__":
        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)
    

个人思考

在解决这个问题时,我意识到动态规划是一种强大的工具,它允许我们在复杂问题中寻找最优解。通过将问题分解为更小的子问题,并存储这些子问题的解,我们可以避免重复计算,从而提高算法的效率。此外,我也认识到在实际应用中,问题的具体细节(如货船的数量限制)对算法的设计和实现有着重要影响。在编写代码时,我特别注意了如何清晰地表达算法的逻辑,以及如何通过测试样例来验证算法的正确性。通过这个过程,我加深了对动态规划和算法调试的理解。