优化青海湖至景点X的租车路线成本 | 豆包MarsCode AI刷题

165 阅读3分钟

原问题描述

油价飞升的今天,我们尽量减少花费。我们出门旅游,有时候租车去旅游也是一种不错的方式。这次我们这次旅游是从「青海湖」到「景点 X」,景点 X 可以是「敦煌」、「月牙泉」等,线路的路径是唯一的,假设我们每走 1 km 消耗 1 L 的油,车油箱容量 400L。比如:如果「景点 X」是敦煌,我们在青海湖租车前油箱是 200L 的,在「景点 X」(敦煌)还车的时候也是 200L 的,路上有很多加油站,加油站在青海湖和「景点 X」的连线上。

输入格式

第 1 行表示「青海湖」到「景点 X」的距离,距离最远不超过 10000 km。 第 2 行表示接下来 N 行表示 N 个加油站(N 为正整数)。 接下来 N(1 <= N <= 100)行表示,每一个加油站情况。每一个加油站包括距离「景点 X」的距离 a km(0 <= a <= 10000),以及每升汽油的价格 b 元(0 <= b <= 2000),a 和 b 均为正整数。

输出格式

如果不能到达目的地「景点 X」,输出 Impossible。 如果能到达目的地「景点 X」,输出最小花费多少元。

输入样例:

500 4 100 1 200 30 400 40 300 20

输出样例:

4300

思路: 使用贪心算法+模拟求解,如果数据规模更大可以使用数据结构优化

先对加油站以离起点的距离为第一关键字进行排序,然后开始第一层循环枚举加油站。假设当前加油站为X,第二层循环枚举下一个油价比X的油价便宜的加油站,假设为Y,我们是否要进行加油要加多少油,需要根据Y来决定,如果X到Y的距离d大于400,那我们直接把油加满就可以了,因为后面到Y之前不可能有比X油价更便宜的加油站了,如果小于400的话,那我们只需要加到d就可以了,然后在Y加油站再考虑加油。如果没有下一个油价比X便宜的加油站了,那我们就直接加满就行了,但是同时需要根据到终点的距离来判断加多少,不然到终点了可能油量大于200。

需要判断一下无解的情况

1.如果第一个加油站离起点站大于200

2.如果两个加油站相隔大于400

3.终点站与最后一个加油站距离大于200

4.没有加油站,起点不同于终点

  • 初步设计为O(n²)的复杂度,因为对于每个加油站可能需要遍历后续所有加油站以选择合适的加油时机。
  • 可以通过使用单调栈预处理下一个油价较低的加油站,将复杂度优化至O(nlogn)。

代码:

def __init__(self, d, w):
        self.d = d
        self.w = w
def solution(distance, n, gas_stations):
    e = [Node(0, 0)] * (n + 2)
    for i in range(n):
        e[i + 1] = Node(gas_stations[i][0], gas_stations[i][1])
    e[n + 1] = Node(distance, float('inf'))
    e.sort(key=lambda x: x.d)
    for i in range(n + 1):
        if e[i].w == float('inf'):
            n = i - 1
            break
    if n == 0 or e[1].d > 200 or e[n + 1].d - e[n].d > 200:
        return -1
    for i in range(1, n + 1):
        if e[i].d - e[i - 1].d > 400:
            return -1
    ans = 0
    now = 200#代表当前汽车剩余油量
    for i in range(1, n + 1):
        num = e[i].d - e[i - 1].d
        now -= num
        flag = 0
        for j in range(i + 1, n + 1):
            if e[j].w < e[i].w:
                flag = 1
                dist = e[j].d - e[i].d
                if now < dist:
                    if dist > 400:
                        ans += (400 - now) * e[i].w
                        now = 400
                    else:
                        ans += (dist - now) * e[i].w
                        now = dist
                break
        if flag == 0:
            dist = e[n + 1].d - e[i].d
            if dist >= 200:
                ans += (400 - now) * e[i].w
                now = 400
            else:
                ans += (dist + 200 - now) * e[i].w
                now = dist + 200
     return ans