华为OD 流浪地球

题目描述

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

  1. 初始状态下所有的发动机都是未启动状态
  2. 发动机启动的方式分为“手动启动”和“关联启动”两种方式
  3. 如果在时刻 1 一个发动机被启动,下一个时刻 2 与之相邻的两个发动机就会被“关联启动”
  4. 如果准备启动某个发动机时,它已经被启动了,则什么都不用做
  5. 发动机 0 与发动机 N-1 是相邻的

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

输入描述

第一行两个数字 N 和 E,中间有空格

  • N 代表部署发动机的总个数,1 < N ≤ 1000
  • E 代表计划手动启动的发动机总个数,1 ≤ E ≤ 1000,E ≤ N

接下来共 E 行,每行都是两个数字 T 和 P,中间有空格

  • T 代表发动机的手动启动时刻,0 ≤ T ≤ N
  • P 代表次发动机的位置编号,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。

import java.util.Scanner;
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    static Map<Integer, Set<Integer>> toDeal = new HashMap<Integer, Set<Integer>>();
    static Map<Integer, Set<Integer>> hasDeal = new
    HashMap<Integer, Set<Integer>>();
    static int total = 0;
    static int all = 0;
    static int[] dealNums;//标记是否已启动

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int [] firstLine = Arrays.stream(in.nextLine().split(" ")).mapToInt(
                               Integer::parseInt).toArray();
        all = total = firstLine[0];
        dealNums = new int[total];
        int k = firstLine[1];
        for (int i = 0; i < k; i++) {
            int [] nums = Arrays.stream(in.nextLine().split(" ")).mapToInt(
                              Integer::parseInt).toArray();
            Set<Integer> set = toDeal.get(nums[0]);
            if (set == null) {
                set = new HashSet<Integer>();
            }
            set.add(nums[1]);
            toDeal.put(nums[0], set);
        }


        for (int i = 0; i < all; i++) {
            if (total > 0) {
                start(i);
            } else {
                System.out.println(hasDeal.get(i - 1).size());
                Set<Integer> set = hasDeal.get(i - 1);
                StringBuilder builder = new StringBuilder();
                set.forEach(e->{
                    builder.append(e).append(" ");
                });
                System.out.println(builder.toString().substring(0, builder.length() - 1));
                break;
            }
        }
    }

    //i时刻启动的发动机
    public static void start(int i) {
        if (toDeal.get(i) != null) {
            Set<Integer> set = toDeal.get(i);
            set.forEach(e-> {
                //判断是否已处理过
                if (dealNums[e] == 0) {
                    //处理当前时间i
                    dealNums[e] = 1;
                    Set<Integer> subSet;
                    if (hasDeal.get(i) == null) {
                        subSet = new HashSet<Integer>();
                    } else {
                        subSet = hasDeal.get(i);
                    }
                    subSet.add(e);
                    hasDeal.put(i, subSet);
                    total --;
                    //添加下一个时间段要处理的发动机到集合toDeal
                    Set<Integer> nextDeal = toDeal.get(i + 1);
                    if (nextDeal == null) {
                        nextDeal = new HashSet<Integer>();
                    }
                    if (dealNums[(e + 1) % all] == 0) {
                        nextDeal.add((e + 1) % all);
                    };
                    if (dealNums[(e + all - 1) % all] == 0) {
                        nextDeal.add((e + all - 1) % all);
                    };
                    toDeal.put(i + 1, nextDeal);
                }
            });
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值