徒步旅行中的补给问题

#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
int solution(int n, int k, std::vector<int> data) {
  // Edit your code here
  std::vector<std::vector<int>> dp(n,std::vector<int>(k,INT_MAX));
  for(int j = 0; j < k; j++){
    dp[0][j] = data[0]*(j+1);

  }
  for(int i = 1; i < n; i++){
    for(int j = 0; j < k; j++){
       // 尝试从i - 1天的合适状态转移过来取最小值
      if (j < k - 1) {
        dp[i][j] = std::min(dp[i][j], dp[i - 1][j + 1]);
      }
      for(int x = 1; j - x + 1 >= 0; x++){
        dp[i][j] = std::min(dp[i][j], dp[i-1][j - x + 1] + data[i] * x);
      } 
    }
  }
  return dp[n-1] [0];
}

int main() {
  // Add your test cases here
  std::cout << (solution(5, 2, {1, 2, 3, 3, 2}) == 9) << std::endl;
  return 0;
}
  • 首先定义了一个二维的 std::vector 类型的 dp,其大小为 n 行 k 列,并且将所有元素初始化为 INT_MAX。这一步是为了在后续的状态转移过程中方便取最小值操作,因为初始时除了特定情况外,其他状态都视为未确定的极大值。
  • 然后通过一个循环初始化 dp[0][j] 的值为 data[0]*(j + 1)。这里的逻辑是在第一天时,对于不同剩余食物份数 j 的情况,计算其花费。假设第一天购买 j + 1 份食物,那么花费就是当天食物价格 data[0] 乘以购买的份数,这样就完成了第一天所有可能状态的初始化。
  • 外层有两层嵌套 for 循环,外层循环遍历天数 i(从 1 开始到 n - 1),内层循环遍历资源状态 j(从 0 到 k - 1)。
  • 在内层循环中,首先有一个 if 语句:if (j < k - 1)。这里的目的是尝试从 i - 1 天的某个相关状态转移过来取最小值。当 j < k - 1 时,考虑从 dp[i - 1][j + 1] 转移过来,因为这表示前一天剩余食物份数多一份的情况,可能会影响到当前天的最小花费决策。这里需要注意的是,直接取最小值时,由于 dp[i][j] 初始为 INT_MAX,所以要谨慎考虑 dp[i - 1][j + 1] 的值是否合法(不是 INT_MAX),不过在当前代码中没有进行这个判断,这可能会导致一些潜在的错误结果被更新进去。
  • 接着是一个 for 循环:for(int x = 1; j - x + 1 >= 0; x++)。这个循环的目的是考虑在当前站点购买不同份数 x 的食物来更新当前状态 dp[i][j]。循环条件 j - x + 1 >= 0 是为了确保在访问 dp[i - 1][j - x + 1] 时不会越界,它表示前一天剩余食物份数在减去购买的份数 x 后仍然在合法范围内。在循环体中,通过 dp[i][j] = std::min(dp[i][j], dp[i - 1][j - x + 1] + data[i] * x) 来更新当前状态的最小花费。这里计算的是在前一天剩余 j - x + 1 份食物的基础上,购买 x 份食物(花费 data[i] * x)后的总花费,并与当前 dp[i][j] 的值取最小值,以得到当前状态的最小花费。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值