徒步旅行中的补给问题 | 豆包MarsCode AI 刷题

85 阅读4分钟

**引言:**这是一道我解决起来绕了好多弯路的题目,所以写一篇思路做个记录。

问题描述

小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。

现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?


测试样例

样例1:

输入:n = 5 ,k = 2 ,data = [1, 2, 3, 3, 2]
输出:9

样例2:

输入:n = 6 ,k = 3 ,data = [4, 1, 5, 2, 1, 3]
输出:9

样例3:

输入:n = 4 ,k = 1 ,data = [3, 2, 4, 1]
输出:10

最初的思路

第一次看这个题目的时候,我脑子里面冒出来的第一个想法,是动态规划。即设置一个数组用于存储在满足题目条件的前提条件下,第i天所需的最小花费。根据题目条件小R最多只能携带k件食物,那么在状态转移的时候只需要考虑该天及该天之前k天即可。从这些天中选择要价最便宜的一天尽可能购买最多的食物。dp[i]=min(dp[i], dp[j]+data[j]*(i-j)) , i -j <k

这样当从第一天遍历计算到第n天就可以直接获得题目所需要的结果,即小R在保证每天都有食物的前提下,完成这次徒步旅行的最小花费。

我们假设所有的状态变化都是在补给站发生的。

上面的想法似乎很流畅,但是忽略了一个重要的问题,那就是小R会在每一天都消耗一件食物,这也就意味着我们未必只能在i~j区间购买一次,而是可以购买很多次。这就导致我的这种算法获得了错误的结果。

AI的想法

那么如何修正呢,我尝试使用豆包AI文档给予我一些提示帮助。但是结果如下:

数据结构选择

我们可以使用一个数组来存储每天的食物价格。由于我们需要在每天决定购买多少食物,因此需要一个动态规划或贪心算法来解决这个问题。

算法步骤

  1. 初始状态:在第0天,小R没有食物,因此需要从第1天开始考虑。
  2. 状态转移:对于每一天,小R需要决定购买多少食物。由于小R最多只能携带K份食物,因此需要考虑前几天的食物价格和当前天的价格。
  3. 贪心策略:为了最小化花费,小R应该在价格最低的补给站购买尽可能多的食物,直到达到K份或满足未来几天的需求。

伪代码框架


def solution(n, k, data):

    # 初始化总花费

    total_cost = 0

    # 初始化当前携带的食物数量

    current_food = 0

    

    for day in range(n):

        # 如果当前食物不足,需要购买

        if current_food < 1:

            # 计算需要购买的食物数量

            needed_food = min(k, n - day)

            # 购买食物并更新总花费

            total_cost += needed_food * 

            data[day]

            # 更新当前食物数量

            current_food += needed_food

        

        # 每天消耗1份食物

        current_food -= 1

    

    return total_cost

关键步骤

  • 计算需要购买的食物数量:需要考虑当前食物数量、剩余天数以及最大携带量K。
  • 更新总花费:根据购买的食物数量和当天的价格更新总花费。
  • 更新当前食物数量:每天结束时减少1份食物。

但显然它犯了和我一样的错误,甚至连题面上给的样例都无法通过。

修正

实际上只需要简单修改一下状态转移方程,只考虑每天消耗的一件食物可以从距离他前k个补给站进行获取即可。dp[i] = min(dp[i], dp[i-1] + data[j]) 整体代码也很简洁:

dp = [float('inf')] * (n+1)
    dp[0] = 0
    for i in range(1, n+1):  # i 表示第i天
        for j in range(max(0, i-k), i):
            dp[i] = min(dp[i], dp[i-1] + data[j])
    return dp[n]

这个方法的计算复杂度为O(n) 当然也可以看作是定长的滑动窗口维护一个单调数组的方式来进行求解。

尾言

这个题目提醒我要更认真地考虑题目条件,避免遗漏情况。 萌新小白作者欢迎指教。