问题描述
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
测试样例
样例1:
输入:
n = 5 ,k = 2 ,data = [1, 2, 3, 3, 2]
输出:9
样例2:
输入:
n = 6 ,k = 3 ,data = [4, 1, 5, 2, 1, 3]
输出:9
样例3:
输入:
n = 4 ,k = 1 ,data = [3, 2, 4, 1]
输出:10
题目解析
这个题目可以采用动态规划的方法来解决。其基本思想也是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原有问题的解。在这个问题中,我们从第一天开始,根据前一天的状态求解每天中不同状态下的最小花费,再求解下一天的最小花费,由此一步步的到原有问题的解。
题目中没有定义初始状态,因此根据测试样例我们可以给出以下定义,第一天初始时,小R携带的食物为 0 份,然后小R经过补给站购买食物,之后小R消耗一份食物,并到达第二天的补给站。在我们的定义中,每天中,小R首先到达补给站购买食物,之后才消耗一份食物。因此我们可以定义一个二维数组cost_matrix,其中cost_matrix[i][j]表示第 i+1 天小R购买食物后,身上携带 j+1 份食物所需的最小花费。矩阵最后一行代表最后一天经过补给站后小R身上所携带食物数量,小R在最后一天还需消耗一份食物,因此 cost_matrix[-1][0] 即为完成这次徒步旅行的最低花费。
代码解析
以下是以Python语言的题目解析:
def solution(n, k, data):
# 初始化最小花费矩阵,
cost_matrix = [[float("inf")]*k for _ in range(n)]
# 初始化第一天的状态
for i in range(k):
cost_matrix[0][i] = data[0]*(i+1)
# 计算后续每一天的状态
for i in range(1,n):
for j in range(k): # 当前天数携带的食物数量
for l in range(k): # 前一天携带的食物数量
if l-j<=1:
cost = data[i]*abs(l-j-1) # 计算从前一天状态转移到今天状态的成本
# 更新今天携带特定数量食物的最小成本
cost_matrix[i][j] = min(cost_matrix[i][j],cost_matrix[i-1][l]+cost)
return cost_matrix[-1][0]
让我们逐步解析这段代码:
初始化成本矩阵
cost_matrix = [[float("inf")]*k for _ in range(n)]
这里创建了一个大小为 n x k 的二维列表 cost_matrix,用来存储第 i+1 天小R购买食物后,身上携带 j+1 份食物所需的最小花费。初始值设置为无穷大 (float("inf")) 表示尚未计算出到达这些位置的成本。
初始化第一天的成本
for i in range(k):
cost_matrix[0][i] = data[0]*(i+1)
动态规划计算过程
for i in range(1,n):
for j in range(k):
for l in range(k):
if l-j<=1:
cost = data[i]*abs(l-j-1)
cost_matrix[i][j] = min(cost_matrix[i][j],cost_matrix[i-1][l]+cost)
这部分是动态规划的核心部分。它遍历数组中的每个元素(从第二个元素开始,即 i=1 到 i=n-1)以及所有可能的状态 j 和前一位置的所有可能状态 l,即在第 i+1 天,小R在经过补给站后身上剩余 j 份食物这一状态,与前一天小R在经过补给站后身上剩余 l 份食物这一状态之间的关系。如果状态 l 和状态 j 的差值不超过 1,此条件是去除当天小R身上剩余食物比前一天剩余食物-1还少的状态,则计算从状态 l 转换到状态 j 的成本,并更新到达当前位置状态 j 的最小成本。
返回原问题结果
return cost_matrix[-1][0]
返回最后一天(数组的最后一个位置)且处于状态 0 ,即剩余一份食物的最小成本。
个人体会
50.优化青海湖至景点X的租车路线成本这道题与本题类似,都是动态规划类题目,可以做做那道题加强对动态规划方法的理解