稀土掘金AI刷题第83题:小S的货船租贸冒险|豆包MarsCode AI刷题

91 阅读4分钟

文章标题:背包问题解法解析:货船租赁的最大载货量

1. 问题描述

在码头租用货船时,小S希望在给定的预算下,租赁能够承载最大总货物的货船组合。每种货船有固定的数量、租赁成本和最大载货量。问题要求在不超过预算的前提下,选择合适的货船,使得总的载货量最大。

输入:

  • Q:货船的种类数量。
  • V:可用的总预算(单位:元)。
  • ships:一个列表,包含每种货船的数量、租赁价格和载货量。

输出:

  • 该组合下最大承载的货物重量。

2. 解题思路

这个问题实际上是一个“完全背包问题”的变种。每种货船的数量是有限制的,并且每种货船的租赁价格和载货量也是固定的。因此,问题的目标是选择合适的货船,使得在预算内能承载的货物量最大。

背包问题的特点:

  • 在标准的背包问题中,每个物品只有一个,或者只能选择一次。
  • 在完全背包问题中,每个物品可以选择多次,且每种物品的选择数量没有上限。

在本问题中,每种类型的货船可以选择多次,但数量是有限制的。

动态规划解法:

我们可以使用动态规划(Dynamic Programming, DP)来解决此问题,具体做法是维护一个一维数组 dp,其中 dp[i] 表示在预算 i 的情况下,能够承载的最大货物量。

3. 代码详解

def solution(Q, V, ships):
    # dp[i]表示预算为i时可以承载的最大货物量
    dp = [0] * (V + 1)
    
    # 遍历每种货船
    for m, v, w in ships:
        # 采用完全背包的方式
        for j in range(V, v - 1, -1):
            for k in range(1, m + 1):
                if j >= k * v:
                    dp[j] = max(dp[j], dp[j - k * v] + k * w)
                else:
                    break
                    
    return dp[V]

代码解析:

  1. 初始化 dp 数组dp[i] 存储预算为 i 时可以承载的最大货物量,初始值为 0,表示没有货船时,承载量为 0。
  2. 遍历每种货船: 每种货船都有一个最大数量、租赁价格和载货量。对于每种货船,我们将其加入预算不超过 V 的背包中。
  3. 完全背包处理: 采用完全背包的动态规划方式。在内层循环中,遍历从 1m 的所有数量,模拟选择这类货船的次数,并计算选择这些货船后,剩余预算下的最大载货量。
  4. 更新 dp 数组: 每次选择货船时,更新 dp[j] 的值,dp[j] 代表在当前预算下的最大载货量。我们需要对每种选择数量进行比较,保留最大的载货量。
  5. 返回最终结果dp[V] 即为在预算为 V 时能够承载的最大货物量。

4. 图解

为了更好地理解代码的运行过程,可以绘制一张简化版的图解:

假设有以下条件:

  • 货船类型1:[数量2,租赁价格3元,载货量2吨]
  • 货船类型2:[数量3,租赁价格2元,载货量10吨]
  • 可用预算 V = 10

动态规划表 dp 可以在预算从 010 的过程中逐步更新。对于每种货船,我们考虑是否选择该货船,更新对应的 dp 值。

预算dp[预算]选择情况
00
10
221艘船类型1
32
442艘船类型1
54
663艘船类型1
7101艘船类型2
8121艘船类型2 + 1艘船类型1
912
10322艘船类型2 + 1艘船类型1

最终结果 dp[10] = 32,即在预算为 10 元的情况下,可以最大化承载 32 吨货物。

5. 时间复杂度分析

  • 空间复杂度O(V),因为我们只使用了一个大小为 V+1 的一维数组来存储每个预算情况下的最大载货量。

  • 时间复杂度O(Q * V * m),其中:

    • Q 是货船的种类数量。
    • V 是可用的预算。
    • m 是每种货船的最大数量。

对于每个货船类型,我们最多尝试 m 次选择,每次都更新 dp 数组,因此时间复杂度是 O(Q * V * m)

6. 结论

通过动态规划方法,我们能够有效地解决这个“货船租赁最大载货量”的问题。使用完全背包问题的变种,我们通过多次选择货船,确保在不超过预算的情况下,能够承载尽可能多的货物。此算法时间复杂度为 O(Q * V * m),在实际应用中表现良好。