问题描述
小F计划从青海湖出发,前往一个遥远的景点X进行旅游。景点X可能是“敦煌”或“月牙泉”,线路的路径是唯一的。由于油价的不断上涨,小F希望尽量减少行程中的燃油成本。车辆的油箱容量为400L,在起始点租车时,车内剩余油量为 200L。每行驶 1km 消耗 1L 油。沿途设有多个加油站,小F可以在这些加油站补充燃油;此外,到达目标景点X还车的时候,需要保证车内剩余的油至少有 200L。
小F需要你帮助他计算,如果合理规划加油站的加油顺序和数量,最小化从青海湖到景点X的旅行成本(元)。
输入:
- distance:从青海湖到景点X的总距离(km),距离最远不超过 10000 km。
- n:沿途加油站的数量 (1 <= n <= 100)
- gas_stations:每个加油站的信息,包含两个非负整数 [加油站距离起始点的距离(km), 该加油站的油价(元/L)]
输出:
- 最小化从青海湖到景点X的旅行成本(元)。如果无法到达景点X,或者到达景点X还车时油料剩余不足 200L,则需要返回
-1告诉小F这是不可能的任务。
def solution(distance, n, gas_stations):
# 添加起点和终点
gas_stations = [(0, 0)] + sorted(gas_stations) + [(distance, 0)]
n += 2 # 更新站点数量
max_fuel = 400 # 油箱容量
fuel = 200 # 初始油量
cost = 0 # 总花费
for i in range(n - 1):
curr_dist, curr_price = gas_stations[i]
next_dist, _ = gas_stations[i + 1]
# 距离检查:无法到达下一个站点
if next_dist - curr_dist > max_fuel:
return -1
# 如果当前油量不足以到达下一个站点
while fuel < next_dist - curr_dist:
# 找价格最低的加油站加油
min_price_station = min(gas_stations[:i + 1], key=lambda x: x[1] if x[1] > 0 else float('inf'))
refill_amount = min(max_fuel - fuel, next_dist - curr_dist - fuel)
if min_price_station[1] == float('inf') or refill_amount <= 0:
return -1
cost += refill_amount * min_price_station[1]
fuel += refill_amount
# 减去行驶消耗
fuel -= next_dist - curr_dist
# 检查终点是否满足剩余 200L 油量
if fuel < 200:
return -1
return cost
if __name__ == "__main__":
# 测试样例
gas_stations1 = [(100, 1), (200, 30), (400, 40), (300, 20)]
gas_stations2 = [(300, 25), (600, 35), (900, 5)]
gas_stations3 = [(100, 50), (150, 45)]
gas_stations4 = [(100, 10), (200, 20), (300, 30), (400, 40), (600, 15)]
gas_stations5 = [(25, 100)]
print(solution(500, 4, gas_stations1) == 4300)
print(solution(1000, 3, gas_stations2) == -1)
print(solution(200, 2, gas_stations3) == 9000)
print(solution(700, 5, gas_stations4) == 9500)
print(solution(50, 1, gas_stations5) == 5000)
问题分析与思路梳理 小F的旅行规划问题,实际上是一个涉及路径优化、动态资源管理的经典问题。问题的核心是以最小的成本实现从起点到终点的旅程,同时满足车辆的燃油约束和到达终点时的剩余油量要求。这个问题不仅考验我们对贪心算法的理解,还要求我们在设计过程中充分考虑问题的约束条件与边界情况。距离与油箱容量的约束:是否可行性判断
在开始求解之前,我们需要确认每两个连续加油站之间的距离是否超过油箱的最大容量(400L)。如果任意一段距离超过这一上限,无论怎么规划,小F都无法完成行程。这一点体现了问题的“边界性”:一些约束条件在初始阶段就可以决定问题的可解性。因此,提前排除不可行的情形是解题中的重要步骤,也能节省计算资源。
动态油量的规划 在沿途行驶过程中,小F需要动态判断是否需要加油,以及加油的数量。这里体现了一个关键的权衡:如果油量不足以支持下一段路程,就必须加油;每次加油应优先选择油价最低的加油站,同时考虑当前的剩余油量与油箱的容量,确保油量不浪费。这一步的核心逻辑是贪心算法的应用。贪心算法的本质是每一步都做出当前的最优选择,这样可以确保最终的解也接近最优解。
到达终点的油量要求 另一个需要特别注意的地方是终点的油量约束:到达终点时,油箱内必须保留至少200L的油。如果在终点附近无法满足这个条件,也意味着整个行程无解。因此,在规划加油策略时,这一条件会贯穿始终。
排序和处理数据的预处理 为了更高效地解决问题,需要对加油站按距离排序。排序操作的意义在于将问题转化为“从左到右依次决策”的形式,简化逻辑。此外,起点和终点也需要作为特殊的加油站加入列表,起点提供初始油量,终点检验最终条件。
新知识点的延伸与总结 贪心算法的应用场景: 本问题中,通过贪心算法解决局部问题(如选择油价最低的加油站)是高效且合理的。贪心算法的一个特点是:它无法回溯,因此在每一步都需要确保当前选择是对整体有利的。这种方法特别适合解决资源分配、路径规划类的问题。
不断训练贪心思想 贪心算法并不复杂,但正确应用它需要大量实践。关键在于如何识别每一步的最优选择,以及判断这种局部最优是否能推导出全局最优。这种思维的锻炼需要通过不断解决类似的问题,例如背包问题、区间覆盖问题等。
总结与感悟: 青海湖到景点X的最优加油规划问题不仅考察了贪心算法的应用,还启发我更深刻地思考资源管理与动态规划的意义。在解决类似问题时,既要关注算法的实现,也要从问题背景中提炼通用的思想与技巧。学习的过程不止是代码层面的提高,更是思维方式的升级。希望通过对这一问题的探讨,能够帮助我们在今后的学习和实践中更加得心应手。