问题描述
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
动态规划思路
二维DP
状态定义
设 dpi\text{dp}idpi 表示在第 iii 天结束时,剩余 jjj 份食物的情况下的最小花费。
- iii 表示天数(从 1 到 NNN)。
- jjj 表示剩余的食物份数(从 0 到 KKK)。
状态转移
- 每天需要消耗 1 份食物,因此从 dpi−1\text{dp}i-1dpi−1 转移到 dpi\text{dp}idpi。
- 如果在当天补给站购买 xxx 份食物(0≤x≤K−j0 \leq x \leq K - j0≤x≤K−j),需要额外支付 x⋅costx \cdot \text{cost}x⋅cost,且转移自 dpi−1\text{dp}i-1dpi−1。
公式如下:
dpi=min(dpi,dpi−1+x⋅cost)\text{dp}i = \min(\text{dp}i, \text{dp}i-1 + x \cdot \text{cost})dpi=min(dpi,dpi−1+x⋅cost)
其中 xxx 为当天购买的食物数量。
边界条件
一维DP
状态定义
- dp[i]\text{dp}[i]dp[i]: 到达第 iii 天的最小花费。
初始化
- dp[0]=data[0]\text{dp}[0] = \text{data}[0]dp[0]=data[0]: 第一天的花费等于第 0 天的食物价格。
转移方程
代码尝试通过以下两种方式更新 dp[i]\text{dp}[i]dp[i]:
-
不从过去的天数额外购买食物,仅使用前一天的花费转移:
dp[i]=dp[i−1]+data[i]\text{dp}[i] = \text{dp}[i-1] + \text{data}[i]dp[i]=dp[i−1]+data[i]
表示直接从第 i−1i-1i−1 天走到第 iii 天,并支付当前天的食物价格。
-
考虑从过去的 kkk 天中购买的食物来覆盖当天的需求:
dp[i]=min(dp[i],dp[j]+data[j])\text{dp}[i] = \min(\text{dp}[i], \text{dp}[j] + \text{data}[j])dp[i]=min(dp[i],dp[j]+data[j])
其中 jjj 的范围是 [max(0,i−k+1),i)[\max(0, i - k + 1), i)[max(0,i−k+1),i)。它尝试找出从过去 kkk 天内购买食物能否更便宜。
最终结果
- dp[−1]\text{dp}[-1]dp[−1]: 到达第 n−1n-1n−1 天的最小花费。
一维dp代码:
def solution(n, k, data):
dp = [float('inf')] * n
dp[0] = data[0]
for i in range(1, n):
dp[i] = dp[i-1] + data[i]
for j in range(max(0, i - k + 1), i):
dp[i] = min(dp[i], dp[i-1] + data[j])
return dp[-1]