问题描述:
小R正在计划一次从地点A到地点B的徒步旅行,总路程需要 N 天。为了在旅途中保持充足的能量,小R每天必须消耗1份食物。幸运的是,小R在路途中每天都会经过一个补给站,可以购买食物进行补充。然而,每个补给站的食物每份的价格可能不同,并且小R最多只能同时携带 K 份食物。
现在,小R希望在保证每天都有食物的前提下,以最小的花费完成这次徒步旅行。你能帮助小R计算出最低的花费是多少吗?
测试样例:
输入:n = 5, k = 2, data = [1, 2, 3, 3, 2] 输出:9
输入:n = 6, k = 3, data = [4, 1, 5, 2, 1, 3] 输出:9
输入:n = 4, k = 1, data = [3, 2, 4, 1] 输出:10
解题过程:
这道题与另一道补给问题《补给站最优花费问题》很像,但题目限制了携带食物的份数,并且食物是先买后吃。最初我尝试以解决《补给站最优花费问题》为基础,改良后解决这道题。在尝试的过程中,我采取了限制每个补给站的购买份数的策略,但实践告诉我这样的方案是行不通的,并不能直接套用模板,没多久我就放弃了。
经过一段时间的思考,我分析着我自己写的《补给站最优花费问题》的解,脑子里突然冒出了这样一个想法:我在每个补给站都买 k 份食物,之后有更便宜的我再退不就好了!题目要考虑最优解,但实际操作还是得一步一步来,那每一步都要选择局部最优解,在未来情况不清楚的情况下,现有的最优解就是局部最优解,那我把每天的补给站都当作最便宜的来对待不就可以了吗?出于严谨,我仔细盘了一下流程:每到一个补给站,我就购买 k 份食物,1 份留着当天吃,其余的分别分配给未来的几天;到下一个补给站,再买 k 份食物,但购买前要跟已经买的食物作比较,留下更便宜的,把贵的退掉;以此类推。这样一来,每天的食物都是在满足所有规则的前提下的最优解。理论可行,实践如下:
def solution(n, k, data):
# Edit your code here
if k == 1:
return sum(data)
cost = [float("inf")] * (n + k)
for i in range(n):
for j in range(k):
cost[i + j] = min(cost[i + j], data[i])
return sum(cost[:n])
上述代码中,首先设定了一个特解,食物份数上限为 1 时直接返回所有补给站的价格总和,因为这种情况下每天都是买完就吃,不用考虑未来。然后用双层for循环,外层遍历天数(补给站),内层遍历份数,每次遍历取最小值即可。值得一提的是, cost 要额外分配 k 个空间,防止超出索引。为了避免浪费空间,其实也可以用if语句添加条件判断,但这样改,代码并不会变得更易读,而且不如增加个 + k 方便(懒),所以这样就挺好。最后返回 cost 的前 n 个元素的和即可。比较可惜的一点是,我给出的解法的复杂度是 O(n*k),复杂度比较高,但我暂时想不到其他的解法。
提交,完成题解。