每日一题:补给站最优花费问题 | 豆包MarsCode AI刷题
问题描述
小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,小U每天都需要消耗一份食物。在路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,且每个补给站的食物价格各不相同。
小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费最少的钱顺利完成这次旅行。
M:总路程所需的天数。N:路上补给站的数量。p:每个补给站的描述,包含两个数字A和B,表示第A天有一个补给站,并且该站每份食物的价格为B元。
保证第0天一定有一个补给站,并且补给站是按顺序出现的。
测试样例
样例1:
输入:
m = 5 ,n = 4 ,p = [[0, 2], [1, 3], [2, 1], [3, 2]]输出:7
样例2:
输入:
m = 6 ,n = 5 ,p = [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]输出:6
样例3:
输入:
m = 4 ,n = 3 ,p = [[0, 3], [2, 2], [3, 1]]输出:9
上述代码实现了一个动态规划的思路,用来计算在一段时间内的最小食物成本。它根据每天的食物价格动态调整,从多个补给站中选择最优方案。
实现思路
输入参数
-
m:天数(总共持续多少天)。 -
n:补给站的数量。 -
p:一个二维数组,描述每个补给站的信息。每个补给站用一个[day, price]表示,其中:day表示第几天有补给站。price表示该补给站当天的食物价格。
输出结果
返回整个时间段内的最小食物成本。
主要逻辑
-
初始化最小成本和当前最小成本:
min_cost初始化为 0,表示累计的最小食物成本。min_now初始化为第 0 天的补给站价格,表示当前已知的最小价格。
-
遍历每一天:
-
判断当天是否有补给站:
- 有补给站:找到当天的补给价格,将当前最小价格更新为当天价格与之前的最小价格中的较小值。
- 没有补给站:当天的价格直接继承之前的最小价格。
-
将当前最小价格累加到
min_cost中,表示这一天天食物的费用。
-
-
返回结果: 最终累计的
min_cost是整个时间段的最小食物成本。
代码解读
初始状态
min_cost = 0
min_now = p[0][1] # 初始化为第 0 天补给站的价格
- 将总成本初始化为 0。
- 用第 0 天的补给站价格作为当前已知的最小价格。
遍历每一天
for day in range(m):
- 从第 0 天开始,逐天遍历,直到第
m-1天。
检查是否有补给站
if day in [station[0] for station in p]:
- 检查当前天数是否存在补给站。
- 使用列表解析从
p中提取所有有补给站的天数,判断当前天数是否在其中。
有补给站时
for station in p:
if station[0] == day:
result = station[1]
min_now = min(min_now, result)
min_cost += min_now
- 找到当天补给站的价格
result。 - 更新当前的最小价格
min_now为当天价格和之前最小价格中的较小值。 - 累加当天的最小价格到总成本。
没有补给站时
else:
min_cost += min_now
- 直接使用之前已知的最小价格作为当天价格,并将其累加到总成本。
示例解读
示例输入
m = 5
n = 4
p = [[0, 2], [1, 3], [2, 1], [3, 2]]
- 总共 5 天(
m=5)。 - 有 4 个补给站(
n=4),分别在第 0、1、2、3 天,价格为 2、3、1、2。
过程分析
- 第 0 天:补给站价格为 2,
min_now = 2,min_cost = 2。 - 第 1 天:补给站价格为 3,
min_now = min(2, 3) = 2,min_cost = 2 + 2 = 4。 - 第 2 天:补给站价格为 1,
min_now = min(2, 1) = 1,min_cost = 4 + 1 = 5。 - 第 3 天:补给站价格为 2,
min_now = min(1, 2) = 1,min_cost = 5 + 1 = 6。 - 第 4 天:无补给站,价格沿用前一天最小价格
min_now = 1,min_cost = 6 + 1 = 7。
输出结果
7
完整代码
def solution(m, n, p):
# dp数组的含义:第i天结束时剩余j份补给所花费的价钱
dp = [[float('inf')] * (m + 1) for _ in range(m + 1)]
# 标记下一个补给站的索引
index = 0
# 初始化dp数组
for i in range(m + 1):
dp[0][i] = p[index][1] * i
index += 1
# 第i天
for i in range(1, m + 1):
# 剩余j份食物
for j in range(m):
# 剩余的食物足够走完了
if j >= i - m:
dp[i][j] = dp[i - 1][j + 1]
# 不补给的情况
dp[i][j] = dp[i - 1][j + 1]
# 判断今天是否到达补给站
if index < len(p) and p[index][0] == i:
# 有补给站,购买k份食物
for k in range(j + 1):
dp[i][j] = min(dp[i][j], dp[i - 1][j - k + 1] + k * p[index][1])
# 如果今天有补给站,补给站指针移动
if index < len(p) and p[index][0] == i:
index += 1
return dp[m][0]
if __name__ == "__main__":
# Add your test cases here
print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]]) == 7)