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

49 阅读3分钟

问题描述

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

  • Q: 货船的种类数量。
  • V: 李华可用的总预算(单位:元)。
  • ships: 一个列表,其中每个元素是一个元组 [m[i], v[i], w[i]],分别表示第 i 种货船的数量、租赁价格和每艘货船的最大载货量。 这个问题是一个典型的0-1背包问题,其中我们需要在不超过给定预算的情况下最大化总载货量。我们可以使用动态规划来解决这个问题。

思考过程

动态规划解决方案

  1. 定义状态:设 dp[j] 表示在预算为 j 元时能够达到的最大载货量。
  2. 状态转移方程:对于每种货船 i,我们考虑是否将其加入到当前的组合中。如果加入,我们需要检查是否有足够的预算来租用至少一艘这种类型的货船,并且更新当前的最大载货量。
  3. 初始化dp[0] = 0,因为没有预算时,最大载货量为0。
  4. 遍历每种货船:对于每种货船,我们遍历所有可能的预算,从0到V,更新 dp 数组。
  5. 返回结果dp[V] 将是在给定预算下能够达到的最大载货量。

代码提示

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

    • 当前代码中,动态规划数组 dp 的大小是 [Q + 1][V + 1],这是正确的。但是,你需要确保在初始化时,dp[0][j] 和 dp[i][0] 的值是合理的。通常情况下,dp[0][j] 应该初始化为 0,表示在没有选择任何货船时,最大载货量为 0
  2. 动态规划状态转移

    • 当前代码中,状态转移方程是 dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * price] + k * weight)。这个方程是正确的,但你可以考虑优化内层循环的边界条件,以减少不必要的计算。
  3. 边界条件检查

    • 在处理每种货船时,确保 k * price <= j 的边界条件是正确的。如果 k * price > j,则不需要继续计算。

核心代码示例

    int[][] dp = new int[Q + 1][V + 1];  // 创建二维动态规划数组
    for (int i = 1; i <= Q; i++) {
        List<Integer> ship = ships.get(i - 1);
        int num = ship.get(0);
        int price = ship.get(1);
        int weight = ship.get(2);

        for (int j = 1; j <= V; j++) {
            for (int k = 0; k <= num && k * price <= j; k++) {
                dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * price] + k * weight);
            }
        }
    }
    return dp[Q][V];

总结

  • 我们首先初始化一个长度为 V + 1 的数组 dp,所有元素都设置为0。
  • 对于每种货船,我们从 V 到 v 的逆序遍历预算,以确保不会重复使用同一艘船。
  • 对于每个预算 j,如果它可以被当前货船的租赁价格 v 整除,我们就更新 dp[j] 为 dp[j - v] + w 和当前 dp[j] 的最大值。
  • 最后,dp[V] 将是在给定预算下能够达到的最大载货量。

这种方法确保我们考虑了所有可能的货船组合,并选择了在给定预算下能够最大化载货量的组合。