小S的货船租赁冒险题解

67 阅读4分钟

问题描述

小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

解题思路

问题概要

小S希望在预算范围内,租用货船来最大化其总载货量。这是一个多重背包问题的变种,其中:

  • 每种货船类型有一个固定数量限制(类似于有限物品数量)。
  • 每艘货船有固定租赁成本和对应的载货量。

目标是找到在总预算 V 内,货船组合的最大载货量。

问题分析

这是一个非常经典的动态规划背包问题,可以直接把它作为模板题看待。采用最常规的解法:

  1. 状态定义: 定义一个数组 dp[Q][V],表示在预算 V 下租用 Q 艘船,能够租用的最大总载货量。

  2. 状态转移方程: 对于每种货船类型,如果选择租用第 i 类货船,则有:

    • 当租用 k 艘第 i 类货船时,有 0 < k < m[i] 且 k*v[i]<当前剩余的预算j。
    • 需消耗预算 k⋅v[i],获得载货量 k⋅w[i]。

    对应的转移公式为:

    dp[i][j]=Max(dp[i][j],dp[i1][jkvalue]+kweight)dp[i][j] = Max(dp[i][j], dp[i - 1][j - k * value] + k * weight)

  3. 初始条件: dp[0][0]=0,即在预算为 0 ,不租用任何一艘船时,载货量为 0。

  4. 最终结果: 计算并输出 dp[Q][V],即在预算 V 内租用 Q 艘船的最大总载货量。

解题步骤

  1. 输入处理:读取 Q、V、货船数组 ships。
  2. 初始化:构建 DP 数组 dp[Q][V] 并初始化。
  3. 状态转移:逐种货船类型处理,根据多重背包逻辑更新 dp
  4. 输出结果:输出 dp[Q][V]。

总结

通过动态规划和多重背包的优化,不断更新背包的最大利用率,从而达到解题的目的,也保证时间和空间效率。

代码展示

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static int solution(int Q, int V, List<List<Integer>> ships) {
        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 value = ship.get(1);
            int weight = ship.get(2);
            for (int j = 1; j <= V; j++) {
                for (int k = 0; k <= num && k * value <= j; k++) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * value] + k * weight);
                }
            }
        }
        return dp[Q][V];
    }

    public static void main(String[] args) {
        // You can add more test cases here
        List<List<Integer>> ships = new ArrayList<>();
        ships.add(List.of(2, 3, 2));
        ships.add(List.of(3, 2, 10));

        List<List<Integer>> ships2 = new ArrayList<>();
        ships2.add(List.of(30, 141, 47));
        ships2.add(List.of(9, 258, 12));
        ships2.add(List.of(81, 149, 13));
        ships2.add(List.of(91, 236, 6));
        ships2.add(List.of(27, 163, 74));
        ships2.add(List.of(34, 13, 58));
        ships2.add(List.of(61, 162, 1));
        ships2.add(List.of(80, 238, 29));
        ships2.add(List.of(36, 264, 28));
        ships2.add(List.of(36, 250, 2));
        ships2.add(List.of(70, 214, 31));
        ships2.add(List.of(39, 116, 39));
        ships2.add(List.of(83, 287, 4));
        ships2.add(List.of(61, 269, 94));
        ships2.add(List.of(23, 187, 46));
        ships2.add(List.of(78, 33, 29));
        ships2.add(List.of(46, 151, 2));
        ships2.add(List.of(71, 249, 1));
        ships2.add(List.of(67, 76, 85));
        ships2.add(List.of(72, 239, 17));
        ships2.add(List.of(61, 256, 49));
        ships2.add(List.of(48, 216, 73));
        ships2.add(List.of(39, 49, 74));

        System.out.println(solution(2, 10, ships) == 32);
        System.out.println(solution(23, 400, ships2) == 1740);
    }
}