251巧克力板选择问题 困难 | 豆包MarsCode AI刷题

6 阅读3分钟

题解:巧克力背包问题

问题描述

在一次春游中,小M希望尽可能多地携带巧克力板。她拥有 nnn 块巧克力板,每块巧克力的边长为 aia_iai​,而重量则为 ai2a_i^2ai2​。小M有多个不同大小的背包,每个背包都有一个最大承重限制。我们的目标是帮助小M计算在每个背包的最大承重范围内,她最多可以携带多少块巧克力板。

例如,假设小M有5块巧克力板,边长分别为1, 2, 2, 4, 5。对于5个不同的背包,其最大承重分别为1, 3, 7, 9, 15,经过计算,小M能够装入的巧克力块数分别是1, 1, 2, 3, 3。

问题分析

该问题可以归类为一个背包问题,具体来说是0/1背包问题的变种。在0/1背包问题中,每个物品只能被选择一次,且我们需要在给定的重量限制下选择尽可能多的物品。我们可以使用动态规划来解决这个问题。

  1. 巧克力的重量计算: 每块巧克力的重量是边长的平方,即对于边长 aia_iai​,其重量为 ai2a_i^2ai2​。
  2. 背包的承重限制: 对于每个背包,我们需要考虑其最大承重,找出可以装入的巧克力块数。

动态规划思路

我们将使用动态规划来解决这个问题,基本思路如下:

  • 定义一个数组 dp,其中 dp[j] 表示承重为 jjj 时能够装入的最大巧克力块数。
  • 我们遍历每块巧克力板,更新 dp 数组,从后向前更新,以避免在同一轮中重复考虑同一块巧克力。

实现步骤

  1. 初始化

    • 计算每块巧克力的重量。
    • 找到所有背包的最大承重,设为 max_weight
    • 创建一个 dp 数组,大小为 max_weight + 1,初始值为0。
  2. 动态规划填充

    • 对于每块巧克力的重量,从最大承重开始向前更新 dp 数组。
    • 如果当前背包的承重可以装下该巧克力,则更新 dp[j]max(dp[j], dp[j - weight] + 1)
  3. 结果输出

    • 遍历每个背包的最大承重,输出对应的 dp 值。

代码实现

以下是完整的Python代码实现:


def solution(n , m , chocolates, bags):
    # 计算每块巧克力的重量
    weights = [a ** 2 for a in chocolates]
    
    # 找到最大的背包承重限制
    max_weight = max(bags)
    
    # 初始化动态规划数组,大小为 max_weight + 1
    dp = [0] * (max_weight + 1)
    
    # 动态规划求解
    for weight in weights:
        # 从后往前更新 dp 数组
        for j in range(max_weight, weight - 1, -1):
            dp[j] = max(dp[j], dp[j - weight] + 1)
    
    # 针对每个背包的最大承重输出结果
    results = []
    for bag in bags:
        results.append(dp[bag])
    
    return results

# 测试用例:
chocolates = [1, 2, 2, 4, 5]
bags = [1, 3, 7, 9, 15]
print(max_chocolates(chocolates, bags))  # 输出:[1, 1, 2, 3, 3]

代码解析

  • 权重计算:通过列表推导式 weights = [a ** 2 for a in chocolates] 计算每块巧克力的重量。
  • 动态规划数组dp 数组初始化为0,大小为 max_weight + 1,表示每个承重状态。
  • 填充动态规划数组:内层循环从 max_weightweight 更新 dp,确保每块巧克力只被计算一次。
  • 结果生成:最后遍历每个背包的最大承重,从 dp 数组中提取结果。

复杂度分析

  • 时间复杂度:最坏情况下时间复杂度为 O(n⋅m)O(n \cdot m)O(n⋅m),其中 nnn 是巧克力块的数量,mmm 是最大的背包承重。
  • 空间复杂度:使用了 O(m)O(m)O(m) 的空间来存储动态规划数组。