徒步旅行补给问题算法分析笔记|豆包MarsCode AI 刷题
一、问题描述
小 R 计划从地点 A 到地点 B 进行徒步旅行,总行程需 N 天。旅行中每天需消耗 1 份食物,且每天会经过一个补给站,补给站食物价格各异,小 R 最多同时携带 K 份食物。要求在保证每天有食物的前提下,计算完成旅行的最小花费。
输入示例 n = 5, k = 2, data = [1, 2, 3, 3, 2],其中 n 表示旅行天数,k 表示小 R 最多携带的食物份数,data 数组表示每天补给站食物的价格。
解决思路-动态规划思想
使用一个List模拟小 R 的背包。遍历每一天行程,把当天补给站食物加入背包,若背包满(>k),则减少前面加入的食物,食用背包中最小价格的食物。
通过模拟实际的补给和使用食物的过程来计算花费。主要是需要每次遍历都需要找出背包最小值,以及加入删除操作当 k 较大时,可能会影响整体性能。
动态规划步骤:
- 定义动态规划数组
dp[],其中dp[i]表示从第 0 天到第i天完成徒步旅行的最小花费。 - 使用容器
pq存储当前携带的食物价格,模拟小 R 携带的食物,其大小最多为k。 - 初始化
dp[0] = data[0],并将data[0]加入优先队列。 - 对于第
i天(i > 0):先将dp[i - 1]+minPrice的值赋给dp[i];若优先队列大小超过k,则移除pq首元素。
这种思路利用了动态规划的思想,通过记录子问题的最优解来逐步构建全局最优解。遍历为O(n),获取最小值O(k),算法的操作时间复杂度为O(n*k),逻辑较为清晰,代码实现相对简洁。
四、代码实现
以下是思路的 Java 代码实现:
public static int solution(int n, int k, int[] data) {
// Edit your code here
int[] dp = new int[n];
List<Integer> pq = new ArrayList<>();
dp[0] = data[0];
pq.add(data[0]);
for (int i = 1; i < n; i++) {
pq.add(data[i]);
if (pq.size() > k) {
pq.remove(0);
}
dp[i] = dp[i - 1] + Collections.min(pq);
}
return dp[n - 1];
}
五、代码讲解
- 动态规划数组
dp初始化:创建一个长度为n的整数数组dp,用于存储从第 0 天到第i天完成徒步旅行的最小花费。首先将dp[0]初始化为data[0],因为第一天只能在当天的补给站购买食物,此时的最小花费就是第一天补给站食物的价格。 - 模拟优先队列
pq初始化:创建一个ArrayList来模拟优先队列。将第一天补给站食物的价格data[0]添加到pq中。 - 添加当天食物价格到
pq:在每次循环中(对应每一天的行程),将当天补给站食物的价格data[i]添加到pq中。 - 处理超出携带容量的情况:如果
pq的大小(即小 R 携带的食物份数)超过了k,就移除pq中的第一个元素(这里假设pq中第一个元素是最早添加的,通过pq.remove(0)实现)。这一步是为了模拟小 R 最多只能携带k份食物。 - 计算当前天的最小花费
dp[i]:计算第i天的最小花费dp[i]。这里的计算方式是将前一天的最小花费dp[i - 1]加上当前pq中价格最低的食物价格(通过Collections.min(pq)获取)。这种计算方式的逻辑是,小 R 可以选择使用前一天剩下的食物(花费dp[i - 1]),然后再加上今天购买一份最便宜的食物(从pq中获取最小值)的花费。 - 最后,返回
dp[n - 1],即整个徒步旅行n天的最小花费。这个值代表了小 R 完成从地点 A 到地点 B 的徒步旅行,在给定的补给站价格和携带食物份数限制下的最优花费策略的结果。
可以考虑使用优先队列优化