问题描述
小C开了一家水果店,接到一个大订单,需要将 n 个编号为 1 到 n 的水果打包成多个果篮。每个果篮的最大容量为 m 个水果,并且水果的编号必须是连续的。每个果篮的成本是根据水果的体积来计算的,成本公式如下:
其中:
k是果篮中水果的数量。u是果篮中水果的最大体积。v是果篮中水果的最小体积。s是一个常数。
目标是将 n 个水果分成若干个果篮,使得总成本最小。
问题剖析
- 果篮的最大容量:每个果篮最多只能装
m个水果,且水果编号必须是连续的。 - 成本计算公式:对于每个果篮,我们需要计算其最大体积、最小体积,然后根据公式计算该果篮的成本。
- 最小化总成本:我们需要将水果分组成多个果篮,且每个组的水果编号是连续的,目标是使得分组的总成本最小。
解题思路
-
动态规划: 我们可以利用动态规划来解决这个问题。设定
dp[i]表示将前i个水果分成若干个果篮的最小成本。 -
状态转移: 对于每个水果
i,我们可以考虑从j到i这一段水果作为一个果篮,其中j代表上一个果篮的结束位置。通过计算该段水果的最大体积u和最小体积v,可以得到这一段果篮的成本。 -
状态转移公式:
- 对于每一个
i,从i - m到i-1的每一个可能的j都可以形成一个新的果篮。我们需要根据当前的j和i来计算果篮的成本并更新dp[i]。 - 使用最大体积和最小体积来计算当前果篮的成本,更新
dp[i]。
- 对于每一个
-
最终目标: 最终,
dp[n]即为将n个水果分成若干个果篮的最小成本。
代码实现
python
复制代码
def solution(n: int, m: int, s: int, a: list) -> int:
# dp[i]表示前i个水果打包成若干个果篮的最小成本
dp = [float('inf')] * (n + 1)
dp[0] = 0 # 没有水果时,成本为0
# 遍历每个可能的水果数目
for i in range(1, n + 1):
max_val = a[i - 1]
min_val = a[i - 1]
# 尝试将i个水果放到不同的果篮
for j in range(i - 1, max(i - m - 1, -1), -1):
# 更新当前果篮的最大最小体积
max_val = max(max_val, a[j])
min_val = min(min_val, a[j])
# 计算当前果篮的成本
cost = (i - j) * ((max_val + min_val) // 2) + s
# 更新dp[i]的值
dp[i] = min(dp[i], dp[j] + cost)
return dp[n]
# 测试用例
if __name__ == '__main__':
print(solution(6, 4, 3, [1, 4, 5, 1, 4, 1]) == 21)
print(solution(5, 3, 2, [2, 3, 1, 4, 6]) == 17)
print(solution(7, 4, 5, [3, 6, 2, 7, 1, 4, 5]) == 35)
代码解析
-
初始化:
dp数组用于记录到每个水果位置i的最小成本。初始化时,dp[0] = 0,表示没有水果时没有成本。- 其他
dp[i]初始为正无穷,表示还没有计算到达该位置的最小成本。
-
动态规划的状态转移:
- 对于每个位置
i,我们尝试选择一个合适的起始位置j来划定一个新的果篮(a[j...i])。每次更新dp[i],计算从j到i的果篮成本,并更新dp[i]为最小值。
- 对于每个位置
-
成本计算:
- 对每一个划定的果篮,我们计算它的最大值
max_val和最小值min_val,然后根据给定的公式计算成本。
- 对每一个划定的果篮,我们计算它的最大值
-
返回结果:
- 最终
dp[n]给出了最优的打包方案对应的最小成本。
- 最终
时间复杂度分析
- 外层循环遍历所有
n个水果,时间复杂度为O(n)。 - 内层循环会遍历至
m个水果,计算每个果篮的成本,所以最坏情况下每次内层循环的复杂度为O(m)。
因此,总的时间复杂度为 O(n * m)。
刷题思路总结
- 动态规划的应用:通过动态规划思想,我们能够分解问题,将其转化为求解子问题的形式。每个状态
dp[i]表示前i个水果的最小打包成本,而每个子问题dp[i]依赖于前面m个水果的选择情况。 - 状态转移的细节:内层循环的设计是从当前水果位置
i向前探索所有可能的划分位置j。这种方法可以确保每个可能的果篮分组都能被计算到。 - 复杂度控制:虽然内层循环可能看起来有点多余,但通过限制内层循环的最大迭代次数为
m,我们能够控制算法的时间复杂度。 - 数学公式的理解:题目中的成本公式需要理解如何根据最大值、最小值和水果数量来计算成本,这一部分逻辑需要清晰地在代码中实现。
通过这道题,可以进一步加强对动态规划的理解,特别是在涉及最小化或最大化问题时的应用。同时,注意到每个果篮的最大容量和连续性要求,解决了一个实际的分组问题。