题目
小R计划从地点A到地点B进行一次徒步旅行,总路程需要 N 天。为了保持能量,小R每天必须消耗1份食物。每天他会经过一个补给站,可以购买食物进行补充。每个补给站的食物价格可能不同,小R最多只能同时携带 K 份食物。任务是帮助小R计算出以最小的花费完成这次徒步旅行的最低花费。
解题思路
这个问题可以通过贪心算法和优先队列(最小堆)来解决。核心思想是在每一天尽量选择价格最低的食物进行购买,同时保持背包中的食物数量不超过 K 份。
具体步骤
-
初始化:
res:记录总花费。bag:使用一个最小堆来存储当前背包中的食物,以便快速找到并移除价格最低的食物。
-
遍历每一天:
-
检查背包是否为空:
- 如果背包为空,直接购买
K份当天的食物,并将这些食物加入最小堆。
- 如果背包为空,直接购买
-
如果背包不为空:
- 将背包中的食物转移到临时背包
temp中,保留价格最低的食物。 - 如果当天的食物价格更低,则替换掉价格更高的食物。
- 将临时背包中的食物补满到
K份,购买价格最低的食物。
- 将背包中的食物转移到临时背包
-
每天消耗一份食物:
- 优先消耗价格最低的食物,从最小堆中弹出价格最低的食物并减少总花费。
-
-
结束旅行:
- 在旅行结束后,将背包中剩余的食物退还,减少总花费。
代码
import heapq
from typing import List
def solution(n: int, k: int, data: List[int]) -> int:
res = 0
bag = [] # 使用最小堆来存储食物
for i in range(n):
# 如果背包为空,直接买满
if not bag:
for _ in range(k):
heapq.heappush(bag, (data[i], i))
res += data[i]
else:
# 将背包中的食物转移到临时背包中,保留价格最低的食物
temp = []
for _ in range(len(bag)):
price, index = heapq.heappop(bag)
if data[i] < price:
res += data[i] - price # 替换掉价格更高的食物
heapq.heappush(temp, (data[i], i))
else:
heapq.heappush(temp, (price, index))
# 将临时背包中的食物补满到 K 份
while len(temp) < k:
heapq.heappush(temp, (data[i], i))
res += data[i]
bag = temp
# 消耗一份食物,优先消耗价格最低的食物
price, index = heapq.heappop(bag)
res -= price
return res
详细步骤解析
-
初始化:
res初始化为0,记录总花费。bag初始化为一个空的最小堆,用于存储当前背包中的食物。
-
遍历每一天:
-
检查背包是否为空:
- 如果背包为空,直接购买
K份当天的食物,并将这些食物加入最小堆。
if not bag: for _ in range(k): heapq.heappush(bag, (data[i], i)) res += data[i] - 如果背包为空,直接购买
-
如果背包不为空:
- 将背包中的食物转移到临时背包
temp中,保留价格最低的食物。 - 如果当天的食物价格更低,则替换掉价格更高的食物。
temp = [] for _ in range(len(bag)): price, index = heapq.heappop(bag) if data[i] < price: res += data[i] - price # 替换掉价格更高的食物 heapq.heappush(temp, (data[i], i)) else: heapq.heappush(temp, (price, index))- 将临时背包中的食物补满到
K份,购买价格最低的食物。
while len(temp) < k: heapq.heappush(temp, (data[i], i)) res += data[i] bag = temp - 将背包中的食物转移到临时背包
-
每天消耗一份食物:
- 优先消耗价格最低的食物,从最小堆中弹出价格最低的食物并减少总花费。
price, index = heapq.heappop(bag) res -= price
-
-
结束旅行:
- 在旅行结束后,将背包中剩余的食物退还,减少总花费。
while bag: remove = bag.pop(0) res -= data[remove.index]
测试用例解析
测试用例1
输入:n = 5, k = 2, data = [1, 2, 3, 3, 2]
-
第1天:
- 背包为空,购买2份食物,花费
1 + 1 = 2。 bag = [(1, 0), (1, 0)],res = 2。
- 背包为空,购买2份食物,花费
-
第2天:
- 消耗1份食物,花费
-1,res = 1。 - 背包中有1份食物,购买1份食物,花费
2,res = 3。 bag = [(1, 0), (2, 1)]。
- 消耗1份食物,花费
-
第3天:
- 消耗1份食物,花费
-1,res = 2。 - 背包中有1份食物,购买1份食物,花费
3,res = 5。 bag = [(2, 1), (3, 2)]。
- 消耗1份食物,花费
-
第4天:
- 消耗1份食物,花费
-2,res = 3。 - 背包中有1份食物,购买1份食物,花费
3,res = 6。 bag = [(3, 2), (3, 3)]。
- 消耗1份食物,花费
-
第5天:
- 消耗1份食物,花费
-3,res = 3。 - 背包中有1份食物,购买1份食物,花费
2,res = 5。 bag = [(3, 3), (2, 4)]。
- 消耗1份食物,花费
-
结束旅行:
- 退还剩余的食物,花费
-2,res = 3。 - 最终结果:
res = 9。
- 退还剩余的食物,花费
测试用例2
输入:n = 6, k = 2, data = [1, 3, 2, 4, 3, 1]
-
第1天:
- 背包为空,购买2份食物,花费
1 + 1 = 2。 bag = [(1, 0), (1, 0)],res = 2。
- 背包为空,购买2份食物,花费
-
第2天:
- 消耗1份食物,花费
-1,res = 1。 - 背包中有1份食物,购买1份食物,花费
3,res = 4。 bag = [(1, 0), (3, 1)]。
- 消耗1份食物,花费
-
第3天:
- 消耗1份食物,花费
-1,res = 3。 - 背包中有1份食物,购买1份食物,花费
2,res = 5。 bag = [(2, 2), (3, 1)]。
- 消耗1份食物,花费
-
第4天:
- 消耗1份食物,花费
-2,res = 3。 - 背包中有1份食物,购买1份食物,花费
4,res = 7。 bag = [(3, 1), (4, 3)]。
- 消耗1份食物,花费
-
第5天:
- 消耗1份食物,花费
-3,res = 4。 - 背包中有1份食物,购买1份食物,花费
3,res = 7。 bag = [(3, 4), (4, 3)]。
- 消耗1份食物,花费
-
第6天:
- 消耗1份食物,花费
-3,res = 4。 - 背包中有1份食物,购买1份食物,花费
1,res = 5。 bag = [(1, 5), (4, 3)]。
- 消耗1份食物,花费
-
结束旅行:
- 退还剩余的食物,花费
-1,res = 4。 - 最终结果:
res = 11。
- 退还剩余的食物,花费