2.徒步旅行中的补给问题-C++ | 豆包MarsCode AI 刷题

213 阅读4分钟

2.徒步旅行补给问题-C++

1. 问题分析

这是一个典型的动态规划问题,涉及到多阶段决策过程。在这个问题中,我们需要为徒步旅行者规划每天的食物购买策略,使得整个旅程的花费最小。

问题约束:

  1. 旅程总共持续N天
  2. 每天必须消耗1份食物
  3. 每天都可以在补给站购买食物
  4. 同时最多只能携带K份食物
  5. 每个补给站的食物价格不同
  6. 需要保证每天都有食物可以食用

关键思考点:

  1. 每天的决策(购买多少食物)会影响后续天数的决策空间
  2. 需要考虑携带量的上限约束
  3. 当天的决策依赖于当前剩余的食物数量
  4. 最后一天结束时不需要剩余食物

2. 动态规划设计

2.1 状态定义

我们使用二维数组dp[i][j]表示状态:

  • i 表示第几天(0 ≤ i ≤ n)
  • j 表示当天结束时剩余的食物数量(0 ≤ j ≤ k)
  • dp[i][j] 的值表示达到该状态的最小总花费

2.2 状态转移方程

对于当前状态dp[i][j],我们可以通过在第i天购买不同数量的食物来影响第i+1天的状态:

dp[i+1][remainTomorrow] = min(dp[i+1][remainTomorrow], dp[i][j] + buy * data[i])
其中:remainTomorrow = j + buy - 1

2.3 边界条件

  • 初始状态:dp[0][0] = 0,其他状态初始化为INT_MAX
  • 结束状态:最终答案为dp[n][0],表示第n天结束时剩余0份食物的最小花费

3. 算法实现细节

3.1 核心步骤

  1. 创建dp数组并初始化
  2. 对每一天i进行遍历
  3. 对当前剩余食物数量j进行遍历
  4. 对可购买的食物数量buy进行遍历
  5. 更新状态转移方程
  6. 返回最终结果dp[n][0]

3.2 注意事项

  1. 需要注意状态转移时的食物数量约束:
    • 剩余食物数量不能为负
    • 不能超过最大携带量K
  2. 购买数量的选择范围:
    • 最少购买0份
    • 最多购买K-j份(考虑当前剩余量)
  3. 状态转移时需要考虑每天消耗1份食物
#include <vector>
#include <algorithm>
#include <climits>

int solution(int n, int k, std::vector<int> data) {
    // dp[i][j] 表示第i天结束时,剩余j份食物时的最小花费
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(k + 1, INT_MAX));
    
    // 初始化第0天的状态
    dp[0][0] = 0;
    
    // 遍历每一天
    for (int i = 0; i < n; i++) {
        // 遍历当前剩余的食物数量
        for (int j = 0; j <= k; j++) {
            if (dp[i][j] == INT_MAX) continue;
            
            // 遍历今天可以购买的食物数量
            for (int buy = 0; buy <= k - j; buy++) {
                // 明天剩余的食物数量 = 今天剩余的 + 购买的 - 消耗的1份
                int remainTomorrow = j + buy - 1;
                if (remainTomorrow >= 0 && remainTomorrow <= k) {
                    // 更新最小花费
                    if (dp[i + 1][remainTomorrow] > dp[i][j] + buy * data[i]) {
                        dp[i + 1][remainTomorrow] = dp[i][j] + buy * data[i];
                    }
                }
            }
        }
    }
    
    // 返回最后一天剩余食物为0时的最小花费
    return dp[n][0];
}

4. 复杂度分析

4.1 时间复杂度

  • O(n * k^2)
    • 需要遍历n天
    • 对每天需要考虑k种剩余状态
    • 对每种状态需要考虑最多k种购买方案

4.2 空间复杂度

  • O(n * k)
    • 需要一个n+1行,k+1列的二维数组存储状态

5. 示例分析

以样例1为例:n=5, k=2, data=[1,2,3,3,2]

最优解决方案:

  1. 第1天:价格1,购买2份,消耗1份,剩余1份
  2. 第2天:价格2,购买1份,消耗1份,剩余1份
  3. 第3天:价格3,购买1份,消耗1份,剩余1份
  4. 第4天:价格3,购买1份,消耗1份,剩余1份
  5. 第5天:价格2,购买0份,消耗1份,剩余0份

总花费 = 12 + 21 + 31 + 31 + 2*0 = 9

这个方案是最优的,因为:

  1. 充分利用了第1天的最低价格
  2. 在价格较高的日子(第3、4天)只购买必需的食物
  3. 合理利用了携带限制,保证了食物供应
  4. 最后一天正好用完所有食物

6. 总结

这道题目是一个典型的动态规划问题,它的难点在于:

  1. 状态的定义需要同时考虑天数和剩余食物量
  2. 状态转移时需要考虑多个约束条件
  3. 需要合理处理购买决策以实现最小花费

通过动态规划的方法,我们可以在多项式时间内得到最优解。这种解法具有较好的扩展性,如果需要添加新的约束条件(如食物保质期),也可以通过修改状态定义和转移方程来适应。