38.补给站最优花费问题
问题描述
小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,她每天都需要消耗一份食物。在这段路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,并且每个补给站的食物价格各不相同。
小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费 最少的钱 顺利完成这次旅行。
- M:总路程所需的天数。
- N:路上补给站的数量。
- p:每个补给站的描述,包含两个数字 A 和 B,表示第 A 天有一个补给站,并且该站每份食物的价格为 B 元。
保证第0天一定有一个补给站,并且补给站是按顺序出现的。
示例
输入:
-
m = 5,n = 4,p = [[0, 2], [1, 3], [2, 1], [3, 2]]- 输出:
7
- 输出:
-
m = 6,n = 5,p = [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]- 输出:
6
- 输出:
-
m = 4,n = 3,p = [[0, 3], [2, 2], [3, 1]]- 输出:
9
- 输出:
解题思路
为了帮助小U以最低的花费完成旅程,我们可以利用动态规划的方法。以下是解题步骤:
-
动态规划表定义:
- 定义一个数组
dp[i],表示在第i天结束时的最小花费。
- 定义一个数组
-
初始化:
dp[0] = 0,因为在第0天不需要花费。
-
状态转移:
- 对于每一天,从
1到M,遍历每个补给站,检查在当前天数之前的补给站,计算从该补给站到当前天的购买成本。 - 更新
dp[i]为当前计算出的最小花费。
- 对于每一天,从
-
结果输出:
- 返回
dp[m],即第 M 天的最小花费。
- 返回
解题代码
def solution(m, n, p):
# dp[i] 表示在第 i 天结束时的最小花费
dp = [float('inf')] * (m + 1)
# 初始化第0天的花费
dp[0] = 0
# 遍历每一天
for i in range(1, m + 1):
# 遍历每个补给站
for j in range(n):
if p[j][0] < i:
# 计算从第 p[j][0] 天到第 i 天的成本
cost = (i - p[j][0]) * p[j][1]
dp[i] = min(dp[i], dp[p[j][0]] + cost)
return dp[m]
# 测试样例
print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]])) # 输出 7
print(solution(6, 5, [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]])) # 输出 6
print(solution(4, 3, [[0, 3], [2, 2], [3, 1]])) # 输出 9
解题思路详细解析
在上述代码中,我们使用了一个动态规划数组 dp 来存储每一天结束时的最低花费。我们先初始化第0天的花费为0,表示小U在出发之前并不需要花费。
通过双重循环,外层循环遍历每一天,内层循环遍历所有补给站。我们检查每个补给站是否在当前天之前,然后计算从该补给站到当前天的成本。如果这一成本加上到达补给站的最低花费小于当前记录的最小花费,我们就更新 dp[i]。
最终,dp[m] 将包含小U完成旅行所需的最低花费。
复杂度分析
- 时间复杂度:O(M * N),最坏情况下,我们需要遍历每一天并检查所有补给站,这可能会导致 M 天和 N 个补给站相乘的复杂度。
- 空间复杂度:O(M),我们使用一个一维数组
dp存储每一天的最小花费,所需额外的空间与天数成正比。