流浪地球 - 华为OD机试真题(E卷、Java)

针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。

有兴趣的同学可以扫码添加我们的微信(code5bug)了解,免费试课一下。

在这里插入图片描述

题目描述

流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N。

​ 1). 初始状态下所有的发动机都是未启动状态;

​ 2). 发动机启动的方式分为”手动启动”和”关联启动”两种方式;

​ 3). 如果在时刻1一个发动机被启动,下一个时刻2与之相邻的两个发动机就会被"关联启动”;

​ 4). 如果准备启动某个发动机时,它已经被启动了,则什么都不用做;

​ 5). 发动机0与发动机N-1是相邻的;

地球联合政府准备挑选某些发动机在某些时刻进行"手动启动”。当然最终所有的发动机都会被启动。
哪些发动机最晚被启动呢?

输入描述

第一行两个数字N和E,中间有空格N代表部署发动机的总个数,E代表计划手动启动的发动机总个数 1

接下来共E行,每行都是两个数字T和P,中间有空格T代表发动机的手动启动时刻,P代表此发动机的位置编号。0 <= T <= N 0 <= P < N

输出描述

第一行一个数字N,以回车结束N代表最后被启动的发动机个数

第二行N个数字,中间有空格,以回车结束每个数字代表发动机的位置编号,从小到大排序

示例1

输入:
8 2
0 2
0 6

输出:
2
0 4

说明:
8个发动机;
时刻0启动(2,6);
时刻1启动(1,3,5,7)(其中1,3被2关联启动,5,7被6关联启动)
时刻2启动(0,4)(其中0被1,7关联启动,4被3,5关联启动);
至此所有发动机都被启动,最后被启动的有2个,分别是0和4。

Java

import java.util.*;
/**
 * @author code5bug
 */
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取N和E
        int n = scanner.nextInt();
        int e = scanner.nextInt();

        // 优先队列,根据启动时刻排序,时刻越早优先级越高
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));

        // 读取E行手动启动的事件
        for (int i = 0; i < e; i++) {
            int t = scanner.nextInt();
            int p = scanner.nextInt();
            pq.offer(new int[]{t, p});
        }

        // 已经启动的发动机集合
        Set<Integer> started = new HashSet<>();

        // 记录最后一批启动的发动机
        List<Integer> last = new ArrayList<>();

        // BFS 执行,处理每个时刻的启动事件
        while (!pq.isEmpty()) {
            last.clear();  // 清空上一轮启动的发动机

            // 获取当前时刻启动的所有发动机
            int time = pq.peek()[0];  // 当前时刻
            while (!pq.isEmpty() && pq.peek()[0] == time) {
                int p = pq.poll()[1]; // 发动机位置

                // 如果该发动机已经启动,跳过
                if (started.contains(p)) {
                    continue;
                } else {
                    // 启动该发动机
                    started.add(p);
                    last.add(p);

                    // 启动该发动机后,需要启动它的相邻发动机(循环队列)
                    int lp = (p - 1 + n) % n;  // 左邻居
                    int rp = (p + 1) % n;      // 右邻居

                    // 如果左邻居没有启动,安排它在下一个时刻启动
                    if (!started.contains(lp)) pq.offer(new int[]{time + 1, lp});

                    // 如果右邻居没有启动,安排它在下一个时刻启动
                    if (!started.contains(rp)) pq.offer(new int[]{time + 1, rp});
                }
            }
        }

        // 最后启动的发动机从小到大排序
        Collections.sort(last);

        // 输出最后被启动的发动机的数量和编号
        System.out.println(last.size());
        for (int i = 0; i < last.size(); i++) {
            if (i + 1 == last.size()) {
                System.out.println(last.get(i));
            } else {
                System.out.print(last.get(i) + " ");
            }
        }
    }
}

1. 题目类型

这道题是一个典型的 广度优先搜索(BFS) 问题。我们需要模拟发动机的启动过程,找到最后被启动的发动机。

2. 解题思路
  1. 输入解析:读取 NE,其中 N 代表发动机的总数,E 代表计划手动启动的发动机的数量。接着读取每个手动启动事件,包括启动的时刻和发动机的位置编号。
  2. 优先队列(PriorityQueue):为了保证每次最早启动的发动机被处理,我们使用 Java 中的 优先队列。队列中的元素是 (启动时刻, 发动机位置) 这样的二元组,优先级是按时刻从小到大排序的。
  3. BFS 执行
    • 对于每个启动时刻,遍历所有在该时刻启动的发动机。
    • 如果该发动机尚未启动,则将其启动,并安排它的相邻发动机在下一个时刻启动。
    • 使用 HashSet 来记录已启动的发动机,避免重复启动。
  4. 输出最后被启动的发动机:在 BFS 完成后,所有发动机都已启动。最后启动的发动机是那些在最晚时刻启动的发动机。

整理题解不易, 如果有帮助到您,请给点个赞 ‍❤️‍ 和收藏 ⭐,让更多的人看到。

你可能感兴趣的:(华为od,java,数据结构,算法,面试,机试)