2.徒步旅行补给问题-C++
1. 问题分析
这是一个典型的动态规划问题,涉及到多阶段决策过程。在这个问题中,我们需要为徒步旅行者规划每天的食物购买策略,使得整个旅程的花费最小。
问题约束:
- 旅程总共持续N天
- 每天必须消耗1份食物
- 每天都可以在补给站购买食物
- 同时最多只能携带K份食物
- 每个补给站的食物价格不同
- 需要保证每天都有食物可以食用
关键思考点:
- 每天的决策(购买多少食物)会影响后续天数的决策空间
- 需要考虑携带量的上限约束
- 当天的决策依赖于当前剩余的食物数量
- 最后一天结束时不需要剩余食物
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 核心步骤
- 创建dp数组并初始化
- 对每一天i进行遍历
- 对当前剩余食物数量j进行遍历
- 对可购买的食物数量buy进行遍历
- 更新状态转移方程
- 返回最终结果dp[n][0]
3.2 注意事项
- 需要注意状态转移时的食物数量约束:
- 剩余食物数量不能为负
- 不能超过最大携带量K
- 购买数量的选择范围:
- 最少购买0份
- 最多购买K-j份(考虑当前剩余量)
- 状态转移时需要考虑每天消耗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,购买2份,消耗1份,剩余1份
- 第2天:价格2,购买1份,消耗1份,剩余1份
- 第3天:价格3,购买1份,消耗1份,剩余1份
- 第4天:价格3,购买1份,消耗1份,剩余1份
- 第5天:价格2,购买0份,消耗1份,剩余0份
总花费 = 12 + 21 + 31 + 31 + 2*0 = 9
这个方案是最优的,因为:
- 充分利用了第1天的最低价格
- 在价格较高的日子(第3、4天)只购买必需的食物
- 合理利用了携带限制,保证了食物供应
- 最后一天正好用完所有食物
6. 总结
这道题目是一个典型的动态规划问题,它的难点在于:
- 状态的定义需要同时考虑天数和剩余食物量
- 状态转移时需要考虑多个约束条件
- 需要合理处理购买决策以实现最小花费
通过动态规划的方法,我们可以在多项式时间内得到最优解。这种解法具有较好的扩展性,如果需要添加新的约束条件(如食物保质期),也可以通过修改状态定义和转移方程来适应。