绿洲之旅|豆包MarsCord AI刷题

90 阅读5分钟

问题描述

小U正在准备穿越一片广阔的沙漠。沙漠里有多个绿洲,每个绿洲设有补给站。所有补给站的收费相同,但提供的水量不同。从起点到终点共有 (D) 公里,小U需要规划在哪些补给站停留,以保证整个旅途中水的供应。

起点到终点的距离为 (D) 公里,小U初始携带 (W) 升水,每行走 1 公里消耗 1 升水。小U希望通过最少的补给次数安全到达终点。每个补给站的位置由 position[i] 表示,距离起点的公里数,supply[i] 表示该站可以提供的水量,单位为升。

请你帮助小U计算,要安全到达终点至少需要补给几次,或者判断是否根本无法到达终点,此时输出-1。

1. 问题分析

小U需要从起点到终点,确保途中水量充足,目标是最少的补给次数

已知条件

  • 总距离为 DDD 公里。
  • 初始携带 WWW 升水。
  • 每行走 1 公里消耗 1 升水。
  • 每个补给站的位置 position[i]\text{position}[i]position[i] 和提供的水量 supply[i]\text{supply}[i]supply[i]。

目标

计算至少需要补给几次,或者判断是否无法到达终点。


2. 解题思路

(1) 核心问题

  • 每次在水量耗尽前找到一个最优补给站,保证后续能够走得更远。
  • 如果在某一位置没有可用补给站,并且水量不足以继续前进,则无法到达终点。

(2) 贪心策略

为了尽量减少补给次数,小U每次到达补给站时,应优先选择提供最大水量的站点,以延长续航距离。这是因为选择补给最多的站点可以减少未来的补给需求。


3. 贪心算法的步骤

  1. 按位置排序

    • 按照 position[i]\text{position}[i]position[i] 对补给站排序,保证按前进方向遍历。
    • 方便模拟小U的行进过程。
  2. 初始化状态

    • 当前水量为 WWW。
    • 当前所在位置为 0。
    • 记录补给次数 count=0\text{count} = 0count=0。
    • 用一个最大堆(优先队列)来存储当前可用的补给站提供的水量(按降序)。
  3. 模拟行进

    • 遍历所有补给站,依次检查是否可以到达该站。
    • 如果当前水量不足以到达下一个站点,从堆中取出最大水量的补给站补给,增加补给次数。
    • 如果堆为空且水量不足,则无法到达,输出 -1。
  4. 到达终点检查

    • 模拟到达终点的过程。如果终点前水量不足但仍有补给站可用,继续从堆中补充。
    • 如果最终水量仍不足,则无法到达终点。

4. 算法实现

伪代码

python
复制代码
def min_refills(D, W, position, supply):
    # 按位置排序补给站
    stations = sorted(zip(position, supply))
    stations.append((D, 0))  # 添加终点作为虚拟补给站
    
    # 初始化
    current_water = W  # 当前水量
    current_position = 0  # 当前所在位置
    count = 0  # 补给次数
    max_heap = []  # 最大堆,存储当前可用补给站的水量(负数表示最大堆)
    
    for next_position, next_supply in stations:
        distance = next_position - current_position  # 到下一个补给站的距离
        
        # 如果水量不足以到达下一个补给站,从堆中补充水量
        while current_water < distance:
            if not max_heap:  # 堆为空,无水可补
                return -1
            # 从堆中取出最大水量补充
            current_water += -heapq.heappop(max_heap)
            count += 1
        
        # 减少水量并更新当前位置
        current_water -= distance
        current_position = next_position
        
        # 将当前补给站的水量加入堆
        heapq.heappush(max_heap, -next_supply)
    
    return count

5. 复杂度分析

  • 时间复杂度

    • 排序补给站:O(nlog⁡n)O(n \log n)O(nlogn)。
    • 遍历补给站并维护堆:O(nlog⁡n)O(n \log n)O(nlogn)。
    • 总复杂度为 O(nlog⁡n)O(n \log n)O(nlogn)。
  • 空间复杂度

    • 最大堆的空间:O(n)O(n)O(n)。

6. 示例分析

示例 1

plaintext
复制代码
输入:
D = 25
W = 10
position = [10, 15, 20]
supply = [10, 5, 5]

小U正在准备穿越一片广阔的沙漠。沙漠里有多个绿洲,每个绿洲设有补给站。所有补给站的收费相同,但提供的水量不同。从起点到终点共有 (D) 公里,小U需要规划在哪些补给站停留,以保证整个旅途中水的供应。

起点到终点的距离为 (D) 公里,小U初始携带 (W) 升水,每行走 1 公里消耗 1 升水。小U希望通过最少的补给次数安全到达终点。每个补给站的位置由 `position[i]` 表示,距离起点的公里数,`supply[i]` 表示该站可以提供的水量,单位为升。

请你帮助小U计算,要安全到达终点至少需要补给几次,或者判断是否根本无法到达终点,此时输出-1。
输出:
1

解释

  • 初始水量为 10,可以到达第一个补给站(位置 10)。
  • 在第一个补给站补充 10 升水,总水量变为 20。
  • 剩余路程为 15 公里,水量足够到达终点,补给次数为 1。

示例 2

plaintext
复制代码
输入:
D = 25
W = 10
position = [10, 15]
supply = [5, 5]

输出:
-1

解释

  • 初始水量为 10,可以到达第一个补给站。
  • 第一个补给站补充 5 升水,总水量为 15。
  • 到第二个补给站后,总水量不足以到达终点,无法完成旅程。

7. 总结

  • 贪心算法每次选择最大补给量的站点,保证最优解。
  • 边界情况如无法到达终点时,及时退出返回 -1。