动态规划问题
旅行中的徒步补给问题
1.题目思路
这段代码的核心思想是动态规划,通过比较直接购买食物和使用之前购买的食物两种策略,来找到每一天的最小花费。代码通过两层循环实现了状态转移,外层循环遍历每一天,内层循环考虑在当前天数下,如何利用之前购买的食物来最小化花费。最终,代码返回的是整个旅程的最小花费。
2.详细方法
创建dp数组:
dp数组用于存储到达每一天结束时的最小花费。数组的长度与data相同,因为data数组包含了每一天的食物价格。
初始化:
dp[0] = data[0]:第一天至少要买一份食物,所以第一天的最小花费就是第一份食物的价格。
动态规划:
外层循环i从1到length-1(length是data数组的长度),代表从第二天开始到最后一天。内层循环j从i-1递减到i-k+1,这个循环的目的是考虑在第i天,小R可以购买从第j天到第i天的食物,以确保在第i天结束时食物刚好吃完。dp[i] = dp[i-1] + data[i]:如果小R在第i天直接购买食物,那么第i天的花费就是前一天的花费加上第i天的食物价格。dp[i] = Math.min(dp[i], dp[i-1] + data[j]):如果小R在第i天使用之前购买的食物,那么第i天的花费就是前一天的花费加上第j天的食物价格。这里取dp[i]和dp[i-1] + data[j]的最小值,以确保找到最小的花费。
返回结果:
return dp[length-1]:返回最后一天的最小花费,即整个旅程的最小花费。
3.代码实现
public class Main {
public static int solution(int n, int k, int[] data) {
// Edit your code here
int length = data.length;
//创建dp数组,这里注意,最后一天已经到了,就不用买食物了
int[] dp = new int[length];
//基本事件:第一天至少要买一份食物
dp[0] = data[0];
//迭代:dp[i]代表当负重为k时,第i天路程的最小花费(食物刚好吃完)
for(int i = 1;i < length;i++){
//直接买
dp[i] = dp[i-1] + data[i];
//之前买的,吃库存
for(int j = i - 1;j >= i-k+1 && j >= 0;j--){
dp[i] = Math.min(dp[i],dp[i-1] + data[j]);
}
}
return dp[length-1];
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(5, 2, new int[]{1, 2, 3, 3, 2}) == 9);
}
}
补给站最优花费问题
1.题目思路
这段代码的核心思想是动态规划,通过比较直接购买食物和使用之前购买的食物两种策略,来找到每一天的最小花费。代码通过两层循环实现了状态转移,外层循环遍历每一天,内层循环考虑在当前天数下,如何利用之前购买的食物来最小化花费。最终,代码返回的是整个旅程的最小花费。
2.详细方法
创建dp数组:
dp数组用于存储到达每一天结束时的最小花费。数组的长度与data相同,因为data数组包含了每一天的食物价格。
初始化:
dp[0] = data[0]:第一天至少要买一份食物,所以第一天的最小花费就是第一份食物的价格。
动态规划:
外层循环i从1到length-1(length是data数组的长度),代表从第二天开始到最后一天。内层循环j从i-1递减到i-k+1,这个循环的目的是考虑在第i天,小R可以购买从第j天到第i天的食物,以确保在第i天结束时食物刚好吃完。dp[i] = dp[i-1] + data[i]:如果小R在第i天直接购买食物,那么第i天的花费就是前一天的花费加上第i天的食物价格。dp[i] = Math.min(dp[i], dp[i-1] + data[j]):如果小R在第i天使用之前购买的食物,那么第i天的花费就是前一天的花费加上第j天的食物价格。这里取dp[i]和dp[i-1] + data[j]的最小值,以确保找到最小的花费。
返回结果:
return dp[length-1]:返回最后一天的最小花费,即整个旅程的最小花费。
3.代码实现
public class Main {
public static int solution(int m, int n, int[][] p) {
// Edit your code here
//dp数组的含义:第i天结束时剩余j份补给所花费的价钱
int[][] dp = new int[m+1][m+1];
//标记下一个补给站的索引
int index = 0;
//初始化dp数组
for(int i = 0;i <= m;i++){
dp[0][i] = p[index][1] * i;
}
index++;
//第i天
for(int i = 1;i <= m;i++){
//剩余j份食物
for(int j = 0;j < m;j++){
//剩余的食物足够走完了
if(j >= i -m){
dp[i][j] = dp[i - 1][j+1];
}
//不补给的情况
dp[i][j] = dp[i-1][j+1];
//判断今天是否到达补给站
if(index < p.length && p[index][0] == i){
//有补给站,购买k份食物
for(int k = 0;k <= j;k++){
dp[i][j] = Math.min(dp[i][j],dp[i-1][j - k + 1] + k * p[index][1]);
}
}
}
//如果今天有补给站,补给站指针移动
if(index < p.length && p[index][0] == i){
index++;
}
}
return dp[m][0];
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(5, 4, new int[][]{{0, 2}, {1, 3}, {2, 1}, {3, 2}}) == 7);
}
}