水果店果篮最小成本问题 | 豆包MarsCode AI刷题

151 阅读3分钟

要解决这个问题,我们需要设计一个动态规划(Dynamic Programming, DP)算法来最小化果篮的总成本。我们会通过计算每种可能的打包方式,并利用动态规划选择最优的方式来达到最小的总成本。

问题分析

给定水果的体积数组 volumes,我们需要将水果按照编号划分成多个果篮。每个果篮最多可以装 m 个水果,且水果的编号必须连续。果篮的成本公式为:

             cost = 𝑘× ⌊ ( 𝑢 + 𝑣 ) / 2 ⌋ + 𝑠

其中,

  • k 是果篮中水果的数量,
  • u 是该果篮中水果的最大体积,
  • v 是该果篮中水果的最小体积,
  • s 是一个常数。

解题思路

  1. 动态规划定义:
    dp[i] 表示前 i 个水果打包成若干果篮后的最小成本。
    我们的目标是计算 dp[n],即所有 n 个水果打包后的最小成本。

  2. 转移方程:
    对于每一个 i,我们可以选择从 ji 这段连续的水果作为一个果篮,其中 ( i - j + 1 \leq m )。然后计算该段水果的成本,最后更新 dp[i]

    dp[i] = min(dp[j] + cost(j+1, i)) for all j such that 1 <= j <= i and i - j + 1 <= m

    其中 cost(j+1, i) 表示从水果 j+1 到水果 i 组成一个果篮的成本。

  3. 计算果篮的成本:
    对于每一个子数组 [j+1, i],我们需要计算:

    • 水果的最大体积 u 和最小体积 v
    • 计算成本公式:cost = 𝑘× ⌊ ( 𝑢 + 𝑣 ) / 2 ⌋ + 𝑠。
  4. 优化:
    每次计算成本时,可以遍历从 ji 的水果,计算 uv。为了优化计算,我们需要合理地更新 uv

代码实现

import math

def min_cost(n, m, volumes, s):
    # dp[i] 表示前i个水果打包的最小成本
    dp = [float('inf')] * (n + 1)
    dp[0] = 0  # 没有水果时成本为0
    
    # 遍历每个可能的果篮结尾
    for i in range(1, n + 1):
        max_vol = -float('inf')
        min_vol = float('inf')
        
        # 遍历当前果篮的起始位置
        for j in range(i, max(i - m, 0), -1):  # 从i往回最多m个
            max_vol = max(max_vol, volumes[j - 1])  # 取最大体积
            min_vol = min(min_vol, volumes[j - 1])  # 取最小体积
            k = i - j + 1  # 水果数量
            cost = k * (math.floor((max_vol + min_vol) / 2)) + s  # 计算当前果篮的成本
            dp[i] = min(dp[i], dp[j - 1] + cost)  # 更新dp[i]
    
    return dp[n]

# 示例测试
n = 6
volumes = [1, 4, 5, 1, 4, 1]
m = 4
s = 3
result = min_cost(n, m, volumes, s)
print(result)  # 输出最小的总成本

代码解释

  1. 初始化 dp 数组:
    dp[i] 表示打包前 i 个水果所需的最小成本。初始时,dp[0] = 0,表示没有水果时没有成本。

  2. 遍历 ij
    外层循环遍历所有可能的果篮结尾 i,内层循环遍历所有可能的果篮起始位置 j,并计算从 ji 构成一个果篮的成本。

  3. 计算成本:
    在内层循环中,维护 max_volmin_vol 来跟踪当前果篮的最大体积和最小体积,并用这些值计算当前果篮的成本。

  4. 更新 dp[i]
    通过比较不同划分方式,更新 dp[i] 为最小的成本。

时间复杂度分析

  • 外层循环遍历 循环遍历 i 从 1 到 n,因此它的迭代次数是 n
  • 内层循环遍历 对于每一个 i,内层循环的迭代次数取决于 i 和 m。 j 从 i 向回最多遍历 m 个元素(即 j 的值从 i 到 max(i - m, 0))。所以,内层循环最多迭代 m 次。

因此,时间复杂度为 O(n * m)。

空间复杂度分析

dp 数组的大小是 n + 1,即需要 O(n) 的空间。

volumes 数组的大小是 n,也是 O(n) 的空间。

因此,空间复杂度为 O(n)。

结果

给定示例输入 n = 6, volumes = [1, 4, 5, 1, 4, 1], m = 4, s = 3,运行代码的输出是:

21

这表明,最优的打包方式使得总成本为 21