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

83 阅读3分钟

题目解析

小C经营着一家水果店,某天他需要将编号为1到 n 的 n 个水果打包成若干果篮。每个果篮有以下限制和要求:

  • 容量限制:每个果篮最多能装 m 个水果。

  • 连续性要求:果篮中的水果编号必须是连续的。

  • 成本计算:每个果篮的成本与其中水果的数量、最大和最小体积以及一个常数 s 相关,计算公式为:

成本=k×(u+v)/2+s成本=k×⌊(u+v)/2⌋+s

其中:

-   k 是果篮中水果的数量。
-   u 是果篮中水果的最大体积。
-   v 是果篮中水果的最小体积。

小C希望将这些水果打包成若干果篮,使得总成本最小。我们的任务是帮助他找到这个最小总成本。

解决思路

要解决这个问题,需要在满足果篮容量和水果编号连续性的前提下,找到一种分组方式,使得所有果篮的总成本最小。这是一个典型的最优化问题,考虑到水果的编号必须连续,适合使用动态规划来解决。

动态规划模型

设定义状态 dp[i] 表示前 i 个水果的最小总成本。我们的目标是求出 dp[n],即所有水果的最小总成本。

状态转移方程

对于每个位置 i,我们可以考虑最后一个果篮包含从某个位置 j 到位置 i 的水果,其中 j 满足 1≤j≤i 且果篮容量不超过 m。因此,状态转移方程为:

dp[i]=mink=1min(m,i)dp[ik]+cost(ik+1,i)dp[i]=min_{⁡k=1}^{min⁡(m,i)}{dp[i−k]+cost(i−k+1,i)}

其中,cost(i−k+1,i) 表示将位置 i−k+1n到 i 的水果打包成一个果篮的成本。

成本计算

为了计算 cost(i−k+1,i),我们需要知道:

  • 水果数量 k:显然就是 i−(i−k+1)+1=k
  • 最大体积 u最小体积 v:需要在区间 [i−k+1,i] 内遍历水果体积来找到。
  • 成本公式
cost=k×(u+v)/2+ssu+v2+scost=k×2u+v+scost=k×⌊(u+v)/2⌋+ss \left\lfloor \frac{u + v}{2} \right\rfloor + scost=k×⌊2u+v​⌋+s

算法实现

在实现动态规划时,需要注意以下几点:

  1. 初始条件:dp[0]=0,表示没有水果时的总成本为0。
  2. 遍历顺序:对于每个 i 从 1 到 n,依次计算 dp[i]。
  3. 优化计算:为了避免重复计算,可以在内层循环中维护当前考虑的水果序列的最大值和最小值。
  4. 边界条件:注意当 i−k≥0 时,才能访问 dp[i−k]。

具体步骤

  • 初始化:设定数组 dp 大小为 n+1,初始值为无穷大(表示尚未计算的状态),并设置 dp[0]=0

  • 动态规划迭代

    • 对于 i 从1到 n:

      • 初始化 u 和 v 为当前水果的体积 a[i]。

      • 对于 k 从1到 min⁡(m,i):

        更新 u 为当前序列的最大体及。

        更新 v 为当前序列的最小体积。

        计算当前果篮的成本:

cost=k×(u+v)/2+s cost=k×⌊(u+v)/2⌋+s

更新 dp[i]

  • 最终答案:dp[n] 即为所求的最小总成本。

总结

通过动态规划的方法,我们将原问题分解为子问题,即求前 iii 个水果的最小总成本。由于水果编号的连续性限制,我们在每一步只需要考虑以当前位置结尾的、长度不超过 mmm 的序列。

在计算每个子序列的成本时,我们利用了前一步计算的最大值和最小值,避免了重复遍历。同时,通过状态转移,我们将问题的规模逐步扩大,最终求得最优解。

这个方法有效地解决了问题,算法复杂度可控,适合在实际应用中使用。

def solution(n: int, m: int, s: int, a: list) -> int:
    dp = [float('inf')] * (n + 1)
    dp[0] = 0  

    for i in range(1, n + 1):
        u = v = a[i - 1]
        for k in range(1, min(i, m) + 1):
            idx = i - k
            if idx >= 0:
                u = max(u, a[idx])
                v = min(v, a[idx])
                kk = k
                cost = kk * ((u + v) // 2) + s
                dp[i] = min(dp[i], dp[idx] + cost)
            else:
                break
    return dp[n]