最小花费徒步旅行问题 | 豆包MarsCode AI刷题

97 阅读4分钟

一、问题描述

小U计划进行一场从地点A到地点B的徒步旅行,总共需要 M 天。在这 M 天的行程中,小U每天需要消耗一份食物,而在路途中会遇到多个补给站。每个补给站提供食物,且不同的补给站在不同的天数提供食物,且价格各不相同。小U的目标是通过在合适的补给站购买食物来最小化旅行中的花费,同时确保每天有足够的食物。

1.输入:

  • M:旅行总天数。
  • N:补给站的数量。
  • p:一个二维数组,每个元素 [A, B] 表示第 A 天有一个补给站,且该站每份食物的价格为 B 元。 保证第 0 天一定有一个补给站,并且补给站是按天数顺序出现的,也就是说p这个二维数组是按照[A,B]里面的A升序排列的。

2.输出:即为最小花费,表示小U完成旅行所需的最少花费。

二、动态规划的思路

因为问题中涉及到 最小成本状态转移,并且有多个子问题可以进行重复利用,所以我们选择用动态规划来解决问题。我们可以由小到大构建出从起点到终点的最优解,这正是动态规划非常经典的应用场景。 我们可以用一个数组 minCost 来表示从第0天到第i天的最小花费。通过逐步更新 minCost 数组,最终得到从起点到终点所需的最小花费。

1. 状态定义

先定义一个数组 minCost,其中 minCost[i] 表示从第 0 天到第 i 天所需要的最小花费。

  • 初始状态:minCost[0] = 0,起点时花费为0。
  • 其余的天数:minCost[i] 初始值为 Infi,表示我们还没有找到到达该天的最小花费。

2. 状态转移

对于每个补给站 p[i] = [day, price],我们尝试从这个补给站出发,并更新从第 day 天到后续天数的最小花费。假设我们从 day 天出发并且在该站购买食物,价格为 price,那么从 dayj 天的花费为 (j - day) * price,因此可以更新数组minCost的值:

minCost[j] = Math.min(minCost[j], minCost[day] + (j - day) * price);

这里的意思是:从 day 天到第 j 天,我们会累积 (j - day) * price 的花费,更新 minCost[j] 为可能的最小值。

通过上述的定义的状态转移规则,最终 minCost[m] 将会是计算出来的完成旅行的最小花费。


三、代码实现

下面是代码的详细实现:

function solution(m, n, p) {
    const minCost = new Array(m + 1).fill(Infi);
    minCost[0] = 0; 
    // 遍历每个补给站
    for (let i = 0; i < n; i++) {
        const [day, price] = p[i];
        // 对于从补给站 day 到每一后续的天数 j,更新最小花费
        for (let j = day; j <= m; j++) {
            // 从补给站 day 到第 j 天的最小花费
            minCost[j] = Math.min(minCost[j], minCost[day] + (j - day) * price);
        }
    }
    return minCost[m];
}

代码解析

  1. 初始化:我们创建了一个长度为 m + 1 的数组 minCost,并将所有的元素初始化为 Infi,代表默认情况下每一天的最小花费是无穷大。minCost[0] = 0 表示起点不需要花费额外的钱。

  2. 遍历补给站:通过遍历每个补给站 [day, price],我们尝试从该补给站出发,更新后续天数的最小花费。

  3. 状态转移:对于每个补给站,从 day 天到后续天数 j,我们更新 minCost[j],确保每一天的最小花费是最优的。

  4. 返回结果:最终,我们返回计算结果 minCost[m]、,它表示从第 0 天到第 m 天所需的最小花费。

四、复杂度分析

  • 时间复杂度:假设补给站的数量为 N,总天数为 M。遍历每个补给站后,我们更新每个后续天数的最小花费。因此,时间复杂度为 O(N * M)

  • 空间复杂度:我们需要一个长度为 M + 1 的数组 minCost 来存储最小花费,因此空间复杂度为 O(M)

五、总结

本题我们学习了如何使用动态规划来解决最小花费路径的问题。在这道题中,关键的动态规划思想是定义一个数组 minCost 来存储从起点到每个天数的最小花费,并通过遍历每个补给站来更新后续天数的最小花费。这个方法不仅帮助我们优化了旅行中的花费问题,还加深了我们对动态规划思想的理解和应用。虽然这道题在动态规划里面算是简单题的一种,但是我们正是要由小见大,由易到难,不断的深入理解和学习动态规划算法,才能为后续深入的学习打下更坚实的基础。