【贪心算法】绿洲之旅:最少次数补给探索

文章目录

问题背景

假设一位旅行者需要穿越一片沙漠,起点到终点的距离为 D 公里,旅行者初始携带了 W 升水,每前进一公里需要消耗一升水。在穿越过程中,沿途会经过 N 个补给站,补给站的位置和可提供的水量分别由数组 positionsupply 描述。

旅行者的目标是用最少的补给次数到达终点。如果在某个时刻发现无法前行,则无法完成任务,输出 -1。

在这一问题中,我们需要兼顾两个核心点:

  1. 每次补给的时机:选择适当的时机进行补给,以保证旅程能够继续。
  2. 补给的优先级:从多个补给选项中,选择能让旅程覆盖最远距离的补给量。

解决思路

从问题描述来看,它具备明显的贪心特性:我们需要在每个关键点(当前位置无水前行时)做出最优决策,尽量选择当前能提供最多水量的补给站,以减少未来补给次数。具体的解决思路如下:

  1. 按距离排序补给站
    补给站的位置不一定是按顺序给出的,因此需要先将它们按距离从小到大排序。这样可以保证旅行者在沿途遇到补给站的顺序与实际前进顺序一致。
  2. 维护一个最大堆记录可选补给量
    在每经过一个补给站时,将其可提供的水量存入最大堆中。当发现当前携带的水量不足以到达下一个目的地时,从堆中取出最大值进行补给。这种策略确保了当前的补给选择是对后续行程最有利的。
  3. 处理终点作为特殊情况
    在所有补给站处理完后,还需要考虑终点的情况。如果当前水量仍不足以到达终点,则需要继续从最大堆中补给,否则任务失败。
  4. 计算补给次数
    每次从堆中取水,即为一次补给。通过计数器记录补给次数,最终返回结果。

贪心算法的优势

这一问题选择贪心算法有以下几个优势:

  1. 局部最优解的有效性
    在每次面临"是否需要补给"的选择时,选用当前能提供最大补给量的站点,总能为未来节省更多水量需求,减少补给次数。
  2. 时间效率高
    贪心算法主要依赖排序和堆操作,时间复杂度为 O(nlog⁡n),非常适合处理大规模输入。
  3. 简单易实现
    贪心算法直接针对问题的局部最优策略构建解决方案,逻辑清晰,代码量少。

实现步骤详解

具体的实现可以分为以下几个步骤:

  1. 输入数据的预处理

    将补给站信息存储为一个二维数组,并按照距离进行排序。

  2. 使用最大堆记录补给量

    遍历每个补给站时,将其补给量加入最大堆。在水量不足时,从堆中提取最大补给量。

  3. 终点检查

    当所有补给站处理完后,仍需检查剩余水量是否能覆盖到终点。如果无法到达,则返回 -1。

  4. 补给次数统计

    每次补充水量,计数器加一,最后输出最少补给次数。

java 复制代码
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

public class travel_lvzhou {

        public static int solution(int d, int w, int[] position, int[] supply) {
            int n = position.length;
            // 补给站按距离排序
            int[][] stations = new int[n][2];
            for (int i = 0; i < n; i++) {
                stations[i][0] = position[i];
                stations[i][1] = supply[i];
            }
            Arrays.sort(stations, Comparator.comparingInt(a -> a[0]));

            // 最大堆存储可以选择的补给量
            PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
            int currentWater = w; // 当前水量
            int refills = 0; // 补给次数
            int prevPosition = 0; // 上一个位置

            for (int i = 0; i <= n; i++) {
                // 当前目标点,补给站或终点
                int currentPosition = (i < n) ? stations[i][0] : d;
                int distance = currentPosition - prevPosition;

                // 如果当前水量不足以到达下一个站点,进行补给
                while (currentWater < distance) {
                    if (maxHeap.isEmpty()) {
                        return -1; // 无法到达
                    }
                    currentWater += maxHeap.poll(); // 从最大堆中取最大水量
                    refills++;
                }

                currentWater -= distance;
                prevPosition = currentPosition;

                // 如果是补给站,将其水量加入堆中
                if (i < n) {
                    maxHeap.offer(stations[i][1]);
                }
            }

            return refills;
        }

        public static void main(String[] args) {
            // You can add more test cases here
            int[] testPosition = {170, 192, 196, 234, 261, 269, 291, 404, 1055, 1121, 1150, 1234, 1268, 1402, 1725, 1726, 1727, 1762, 1901, 1970};
            int[] testSupply = {443, 185, 363, 392, 409, 358, 297, 70, 189, 106, 380, 130, 126, 411, 63, 186, 36, 347, 339, 50};

            System.out.println(solution(10, 4, new int[]{1, 4, 7}, new int[]{6, 3, 5}) == 1);
            System.out.println(solution(2000, 200, testPosition, testSupply) == 5);
        }

}

外链: 绿洲之旅:最少次数补给探索

相关推荐
kim565915 分钟前
excel版数独游戏(已完成)
算法·游戏·excel·数独
cv君38 分钟前
【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
算法
Ocean☾1 小时前
C语言-详细讲解-P1217 [USACO1.5] 回文质数 Prime Palindromes
c语言·数据结构·算法
沐泽Mu1 小时前
嵌入式学习-C嘎嘎-Day08
开发语言·c++·算法
Non importa1 小时前
汉诺塔(hanio)--C语言函数递归
c语言·开发语言·算法·学习方法
跳动的梦想家h1 小时前
黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)
java·开发语言·redis
苹果醋31 小时前
前端面试之九阴真经
java·运维·spring boot·mysql·nginx
ac-er88881 小时前
PHP 二分法查找算法
开发语言·算法·php
哎呦没1 小时前
Spring Boot OA:企业办公自动化的高效路径
java·spring boot·后端
真心喜欢你吖1 小时前
Spring Boot与MyBatis-Plus的高效集成
java·spring boot·后端·spring·mybatis