小S的货船租赁冒险-01背包问题

19 阅读3分钟

问题描述

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

  • Q: 货船的种类数量。
  • V: 小S可用的总预算(单位:元)。
  • 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

解题思路

1. 问题理解

  • 你需要在给定的预算V内,选择不同类型的货船,使得载货总量最大
  • 每种货船都有固定的数量,租赁成本以及最大的载货量

2. 算法思路

  • 定义一个dp数组,使用动态规划来解决这个问题
  • dp数组大小为dp[Q+1][V+1],dp[i][j]表示在前i种货船下在价格为j的条件下,可以装多少货物
  • 整体算法实现采取三层循环的架构
    • 最外层循环表示第i中货船
    • 中间一层循环表示花费j元最多可以装载多少货物
    • 由于我们每种货船有数量限制,所以第三层循环用来计算在j元以内,你可以购买几艘i号船
  • 状态转移
    • 不选择当前i号船 那么dp[i][j] = dp[i-1][j]
    • 选择当前i号船,则需要从预算j中扣除当前i号船的成本,同时增加载货量,即 dp[i][j] = Math.max(dp[i-1][j-numshipmoney]+numshipheight, dp[i][j]);
      • num 表示i号船的数量
      • shipmoney 表示i号船的成本
      • shipheight 表示i号船的载货量

代码实现

    public static int solution(int Q, int V, List<List<Integer>> ships) {
        // Please write your code here
        //初始化dp数组,dp[i][j]表示前i搜货船在价格为j的条件下,最多可以装载多少货物
        int[][] dp = new int[Q+1][V+1];
        for(int i = 1 ; i <= Q; i++){
            List<Integer> ship = ships.get(i-1);
            int shipnum = ship.get(0);
            int shipmoney = ship.get(1);
            int shipheight = ship.get(2);
            for(int j = 0;j<=V;j++){
                //花费j元,找到最多可以装载多少货物
                for(int num = 0 ;num<= shipnum;num++){
                    if(num * shipmoney <= j){
                        dp[i][j] = Math.max(dp[i-1][j-num*shipmoney]+num*shipheight, dp[i][j]);
                    }
                }      
            }
        }
        return dp[Q][V];

    }