问题描述
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
算法使用
dfs
算法思路
-
初始化备忘录:
- 定义一个二维数组
memo,其中memo[i][j]表示在第i天,携带j份食物时的最小花费。数组的大小为n x (k + 1),其中n是天数,k是最大携带食物量。 - 将
memo数组中的所有元素初始化为-1,表示尚未计算。
- 定义一个二维数组
-
定义递归函数:
- 定义一个递归函数
dfs,它接受当前天数i,当前携带的食物量cur,以及总天数n和最大携带食物量k作为参数,并返回从第i天开始到第n天的最小花费。
- 定义一个递归函数
-
处理边界情况:
- 如果
i等于n,即已经到达最后一天,返回0,因为不需要再购买食物。 - 如果
memo[i][cur]不等于-1,表示已经计算过这个状态,直接返回memo[i][cur]。
- 如果
-
计算最小花费:
- 初始化一个变量
res为Integer.MAX_VALUE,用于存储当前状态下的最小花费。 - 遍历所有可能的购买食物量
t,从1到k - cur(即最多可以购买的食物量),计算购买t份食物后的花费,并递归调用dfs函数计算后续天数的最小花费。 - 如果当前携带的食物量
cur不为0,可以选择不购买食物,直接进入下一天,并递归调用dfs函数计算后续天数的最小花费。
- 初始化一个变量
-
更新备忘录:
- 将计算得到的最小花费
res存储到memo[i][cur]中。
- 将计算得到的最小花费
-
返回结果:
solution函数返回从第0天开始,携带0份食物时的最小花费,即dfs(data, k, 0, 0, n)。
代码展示
import java.util.Arrays;
public class Main {
private static int[][] memo;
public static int solution(int n, int k, int[] data) {
// Edit your code here
memo = new int[n][k + 1];
for (int i = 0; i < n; i++) {
Arrays.fill(memo[i], -1);
}
return dfs(data, k, 0, 0, n);
}
public static int dfs(int[] data, int k, int i, int cur, int n) {
if (i == n) {
return 0;
}
if (memo[i][cur] != -1) {
return memo[i][cur];
}
int res = Integer.MAX_VALUE;
// 对于当前天, 可以啥也不干进入下一天, 可以购买若干粮食进入下一天
for (int t = 1; t + cur <= k; t++) {
res = Math.min(res, dfs(data, k, i + 1, cur + t - 1, n) + data[i] * t);
}
res = cur != 0 ? Math.min(res, dfs(data, k, i + 1, cur - 1, n)) : res;
return memo[i][cur] = res;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(5, 2, new int[] { 1, 2, 3, 3, 2 }));
}
}