题目:徒步旅行中的补给问题
1、题目描述
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
2、测试用例
样例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
3、解题思路
(1)问题理解
由题可知,小R需要旅行的天数、路上可以带的食物份数以及旅行站每日商品的价格由我们输入,小R选择的补充方式可以是多样的,而我们需要做的是选出旅行途中的最优解,即最小花费。由我们编写一段代码来计算这段旅程如何进行食物购买及携带才能花费最少的钱走完此段旅程。
所以我们要替小R做出选择,判断每天是否需要购买补给站的食物,以及根据小R能够携带的最多食物量来判断在该补给站需要携带多少份食物等,最终求得该旅行中的最小花费金额及方法。
简单理解如下:
a. 小R每天需要消耗1份食物,且每天经过的补给站食物价格不同。
b. 小R最多只能携带K份食物。
c. 目标是找到在N天内完成旅行所需的最小花费。
(2)数据结构选择
在该题目中,我选择的数据结构是数组和整型变量用来存储和处理信息:
a. 数组(列表):
数组是存储固定大小序列元素的理想选择,因为它提供了快速的随机访问能力。在这个问题中,我们需要存储每天的食物价格和动态规划的中间结果,使用数组最合适。
costs数组:用于存储每天补给站的食物价格。数组的索引代表天数(从0到N-1),数组的值代表对应补给站的食物价格;
dp数组:用于存储动态规划过程中的中间结果。dp[i] 表示到达第 i 天补给站时的最小花费;
b. 整数变量:
整数变量用于存储天数 N 和携带能力 K,因为它们是简单的数值,不需要复杂的数据结构。
N整数:表示总路程需要的天数;
K整数:表示小R最多能同时携带的食物份数;
通过这些数据结构,可以高效地实现动态规划算法,计算出小R完成徒步旅行所需的最低花费。
(3)代码编写步骤
a. 定义问题和输入:
确定输入参数:总天数 N,最大携带食物量 K,以及每天补给站的食物价格列表 costs。
确定输出:小R完成旅行的最小花费。
b. 初始化动态规划数组dp
创建一个数组 dp,长度为 N,用于存储到达每一天的最小花费。
初始化 dp[0] 为 costs[0],因为小R在第一天必须购买食物。
c. 填充动态规划数组
遍历每一天,从第1天到第 N-1 天。
对于每一天 i,考虑所有可能的食物购买策略,即在前一天 j(j 从 i-1 到 max(0, i-K))购买食物,并计算到达第 i 天的最小花费。
更新 dp[i] 为到达第 i-1 天的最小花费加上第 i 天的食物价格。
d. 计算结果:
最小花费存储在 dp[N-1] 中,因为我们需要计算完成整个旅行的最小花费。
(4)代码详解
dp = [[float('inf')] * (k + 1) for _ in range(n + 1)]
#初始化动态规划数组dp
dp[0][0] = 0
#循环遍历天数,进行补给选择和判断
for i in range(1, n + 1):
#循环遍历背包内的食物数量
for l in range(k):
#判断背包内数量绝不超过可带食物数量上限
for j in range(k):
#判断该补给站是否携带食物,如携带带几份
if l - j + 1 >= 0 and l - j + 1 <= k:
dp[i][l] = min(dp[i][l], dp[i - 1][j] + (l - j + 1) * data[i - 1])
# 输出dp,即在第n天结束时,携带0份食物的最小花费
return dp[n][0]
4、试题经验总结
这道题目相对简单,这是一个动态规划问题,要求计算小R在徒步旅行中,面对不同天数和食物价格,以及携带食物数量限制的情况下,如何以最小的花费购买足够的食物以完成整个旅程。
解决这个问题需要定义合适的状态和状态转移方程,通过动态规划的方法找到到达每一天的最小花费,并最终得出整个旅程的最低花费。
该题目:
时间复杂度: 该题目算法中存在嵌套循环,外层循环从第1天到第 N-1 天,内层循环从 max(0, i-K) 到 i-1;内层循环最多迭代 K 次,该循环内还有一个求和操作,计算从第 j+1 天到第 i 天的食物价格总和。这个求和操作的时间复杂度是 O(i-j),最多是 O(K)。
因此,总的时间复杂度是外层循环的迭代次数乘以内层循环的迭代次数和内层循环内的计算复杂度:
O(N)×O(K)×O(K)=O(NK2)O(N)×O(K)×O(K)=O(NK2)
空间复杂度O(n)(其中n为旅行天数)