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

80 阅读4分钟

No83 小S的货船租赁冒险

问题描述:

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

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

问题分析:

1、分析问题类型

在给定预算的条件下,从多种类型的货船中选择合适的组合,使得载货总量最大,这属于背包问题(在有限容量的情况下选择物品以达到某种最优价值)的变形。可以使用动态规划来解决这类问题。

2. 确定状态表示。

定义一个二维数组 dp[i][j],表示在前 i 种货船中,使用不超过 j 元的预算所能获得的最大载货量。

3. 初始化状态

  • 创建一个二维数组 dp,大小为 (Q+1) x (V+1),初始值为 0。
  • i = 0 (也就是还没有选择任何货船种类时),对于所有的预算 j ,如果 j 小于第一种货船的租赁成本 v[0],那么 dp[0][j] = 0,因为此时没办法租用第一种货船,载货量自然为 0;而如果 j 大于等于 v[0],则 dp[0][j] 等于在预算 j 下能租用第一种货船所获得的载货量,也就是 (j / v[0]) * w[0](这里 j / v[0] 表示能租用的第一种货船的数量,向下取整,再乘以每艘的载货量 w[0])。
  • 另外,当 j = 0 (预算为 0 时),无论考虑到第几种货船, dp[i][0] = 0,因为没有预算就租不了任何货船,载货量就是 0。

4. 状态转移方程推导

  • 对于每一种货船 i,遍历所有可能的预算 j

  • 对于每种货船,考虑租用 k 艘(k 从 0 到 m[i]),更新 dp[i][j]

  • 对于 i > 0j > 0 的情况,我们需要考虑是否选择第 i 种货船来更新最大载货量。

  • 有两种选择:

    • 不选第 i 种货船:那么 dp[i][j] = dp[i - 1][j],也就是维持在前 i - 1 种货船、预算为 j 时的最大载货量状态。
    • 选择第 i 种货船:我们要考虑在预算允许的范围内尽可能多地租用第 i 种货船,设能租用的最大数量为 kk 要满足 k <= m[i]k * v[i] <= j),然后计算选择 k 艘第 i 种货船后的载货量,即 k * w[i],再加上用剩余预算 j - k * v[i] 在前 i - 1 种货船中能获得的最大载货量 dp[i - 1][j - k * v[i]]。我们要在所有可能的 k 值中取使得载货量最大的情况。
  • 所以状态转移方程为:dp[i][j] = max(dp[i][j], dp[i-1][j-k*v[i]] + k*w[i]),其中 k 是租用的货船数量。

5. 计算最终结果

  • 通过按照状态转移方程依次填充 dp 数组,最后 dp[Q][V] 就表示在 Q 种货船、预算为 V 元的情况下,所能租用的货船的最大总载货量。

6. 代码

public static int solution(int Q, int V, List<List<Integer>> ships) {
        // Please write your code here
        // Q:货船种类
        // V: 总预算
        // 初始化动态规划数组
        int[][] dp = new int[Q + 1][V + 1];
        // 遍历每一种货船
        for (int i = 1; i <= Q; i++) {
            List<Integer> ship = ships.get(i - 1);
            int m = ship.get(0); // 货船数量
            int v = ship.get(1); // 租赁成本
            int w = ship.get(2); // 载货量

            // 遍历所有可能的预算
            for (int j = 0; j <= V; j++) {
                // 考虑租用 k 艘货船
                for (int k = 0; k <= m && k * v <= j; k++) {
                    // 更新 dp[i][j]
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v] + k * w);
                }
            }
        }

        // 返回最终结果
        return dp[Q][V];
    }