这是一道经典的贪心算法问题。它考验的不仅仅是找到一个看似正确的贪心策略,更是对策略背后逻辑的严谨思考,以及对问题状态的完整建模。很多同学(包括你最初的代码)都会掉入同一个陷阱,这篇题解将带你绕开它。
一辆汽车需要从起点行驶到终点,途中有若干加油站。给定汽车油箱容量、每升油能行驶的距离、以及每个加油站的油价和位置。目标是计算从起点到终点所需的最小花费。如果无法到达,则输出 "No Solution"。
贪心算法的精髓在于每一步都做出当前看起来最优的选择。那么,在这个问题里,当车停在某个加油站 i
时,“最优选择”到底是什么?
这需要分两种情况讨论:
i
更便宜的油站j
即可。j
站所需的油,都是在用“更贵的成本”行驶本可以由“更便宜成本”覆盖的距离,这显然不划算。i
贵(或一样贵)i
的油是接下来一段路程中最划算的了。我们应该充分利用这个优势。所以,应该在当前站把油箱加满,然后径直开往这个可达范围内油价最低的那个油站 k
。k
站,是为了让下一次决策时,我们的起点油价尽可能低。我最初的代码逻辑是:从站 i
找到目标站 j
,然后计算 (a[j].dis - a[i].dis) * a[i].co / per
作为花费。这个公式隐含了一个致命的假设:每次出发时油箱都是空的。
【致命场景】
dist=0, price=5.0
),B站(dist=400, price=10.0
),终点C(dist=600
)。错误逻辑:
(400/10) * 5.0 = 200
元。(200/10) * 10.0 = 200
元。正确逻辑:
50 * 5.0 = 250
元。油箱现有50升。10 * 10.0 = 100
元。结论: 如果不追踪 current_oil
(当前油量)这个状态,你的算法永远无法做出“用之前剩下的便宜油”这种决策,从而导致计算结果偏高。
我最初代码的另一个问题是,在所有可达站里,总是选择那个油价最低的。这在某些情况下不是最优的。正确的做法是区分上述两种情况,做出不同的决策。
为了优雅地实现正确的贪心策略,我们可以做一些巧妙的建模:
current_oil
和 total_cost
两个核心变量。import sys
class Oil:
def __init__(self, co=0, dis=0):
self.co = co
self.dis = dis
input = lambda: sys.stdin.readline().strip()
dis, c, per, start_co, n = map(float, input().split())
n, maxn, a = int(n), c * per, [Oil(start_co, dis=0)]
for i in range(n):
x, y = map(float, input().split())
a.append(Oil(y, x))
a.append(Oil(co=0, dis=dis))
a.sort(key=lambda item: item.dis)
n = len(a) - 1
if a[0].dis or a[1].dis - a[0].dis > maxn:
print("No Solution")
exit()
i, total_cost, current_oil = 0 , 0.0, 0.0
while i maxn:
break
if a[j].co maxn:
break
if a[j].co
解决算法问题,尤其是贪心问题时:
current_oil
就是被遗忘的关键记忆。参与评论
手机查看
返回顶部