CCF-CSP-201812-2-小明放学 JAVA

题目背景

汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。

问题描述

一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。上学

输入格式

输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。
  输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。
  接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,将会耗时 t 秒,此处 t 不超过 106;k=1、2、3 时,分别表示出发时刻,此处的红绿灯状态是红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。

输出格式

输出一个数字,表示此次小明放学回家所用的时间。

样例输入

30 3 30
8
0 10
1 5
0 11
2 2
0 6
0 3
3 10
0 3

样例输出

46

样例说明

小明先经过第一段路,用时 10 秒。第一盏红绿灯出发时是红灯,还剩 5 秒;小明到达路口时,这个红绿灯已经变为绿灯,不用等待直接通过。接下来经过第二段路,用时 11 秒。第二盏红绿灯出发时是黄灯,还剩两秒;小明到达路口时,这个红绿灯已经变为红灯,还剩 11 秒。接下来经过第三、第四段路,用时 9 秒。第三盏红绿灯出发时是绿灯,还剩 10 秒;小明到达路口时,这个红绿灯已经变为红灯,还剩两秒。接下来经过最后一段路,用时 3 秒。共计 10+11+11+9+2+3 = 46 秒。

评测用例规模与约定

有些测试点具有特殊的性质:
  * 前 2 个测试点中不存在任何信号灯。
  测试点的输入数据规模:
  * 前 6 个测试点保证 n ≤ 103。
  * 所有测试点保证 n ≤ 105。

难点: 计算小明到达一个路段时,该路段的红绿灯颜色和红绿灯倒计时

提交结果:
在这里插入图片描述

代码:

import java.util.ArrayList;
import java.util.Scanner;

public class 小明放学 {
    public static void main(String[] args) {
        Scanner ip = new Scanner(System.in);

        // 红1 黄2 绿3 无灯0
        int R = ip.nextInt();// R 完整红灯的时间
        int Y = ip.nextInt();// Y 完整黄灯的时间
        int G = ip.nextInt();// G 完整绿灯的时间

        // 通过的路段数  包括红绿灯路段 和 无灯路段
        int LIGHTNUM = ip.nextInt();

        /*
        *   初始化路段集合
        *   R 完整红灯的时间
        *   Y 完整黄灯的时间
        *   G 完整绿灯的时间
        * */
        LightList LL = new LightList(R,Y,G);

        int lightColor,lightTime;

        for (int i = 0; i < LIGHTNUM ; i++) {
            lightColor = ip.nextInt(); // 灯颜色
            lightTime = ip.nextInt(); // 灯的剩余倒计时

            // 向集合添加一个路段 (灯颜色 + 灯的剩余时间) -> 一个路段
            LL.addLight(lightColor,lightTime);
        }

        // 打印最终结果
        LL.printSUM();

    }

    static class LightList {
        long SUM = 0; // 已用时间
        int passLightNum = 0; // 已经过的路段数
        ArrayList<LightNode> LL; // 存储所有路段 出发时的 灯颜色 + 灯倒计时
        int R,Y,G;

        LightList(int R,int Y,int G) {
            this.R = R;// R 完整红灯的时间
            this.Y = Y;// Y 完整黄灯的时间
            this.G = G;// G 完整绿灯的时间
            this.LL = new ArrayList<>();
        }

        // 创建一个路段
        void addLight(int lightColor, int lightTime) {
            LightNode LN = new LightNode(lightColor,lightTime,this.R,this.Y,this.G);
            LL.add(LN); // 将路段添加到LightList中
            LightNode nowLN = LL.get(passLightNum); // 现在正在走的路段
            this.SUM = nowLN.changeLightColor(this.SUM); // 获取走完该路段之后,最新的已用时间
            this.passLightNum ++;
        }

        void printSUM() {
            System.out.println(this.SUM);
        }
    }

    static class LightNode {
        static int R;
        static int Y;
        static int G;
        int lightColor; // 0直接通过 红1 黄2 绿3
        int lightTime; // 灯倒计时时间

        /*
        *   初始化所有路段
        *   lightColor 灯的颜色  用于创建一个路段
        *   lightTIme 灯的倒计时  用于创建一个路段
        *   R 红灯的完整倒计时
        *   Y 黄灯的完整倒计时
        *   G 绿灯的完整倒计时
        * */
        LightNode(int lightColor, int lightTime,int R,int Y,int G) {
            LightNode.R = R;
            LightNode.Y = Y;
            LightNode.G = G;
            this.lightColor = lightColor;
            this.lightTime = lightTime;
        }


        /*
        *   改变现在路段的灯颜色和灯倒计时 然后计算
        *   形参:已用时间
        *   return:最新已用时间
        * */
        long changeLightColor(long sum) {
            // sum为小明到达该路段时,之前走过的所有路段的秒数
            long cpSum = sum;

            // 如果为无灯路段 则直接通过 并加上通过所需时长
            if (this.lightColor == 0) {
                sum += this.lightTime;
            }
            // 如果为红绿灯路段
            else {
                // 没有这一步会运行超时
                // 解释:假如 三个灯的总倒计时时长为 time,则小明每走过一次time秒,所有红绿灯回归原来的倒计时
                cpSum %= (LightNode.G + LightNode.R + LightNode.Y);

                /*
                *   计算到达该路段时,该路段现在的 (灯颜色 和 灯倒计时秒数)
                *
                *   如果cspSum - this.lightTime > 0,
                *   说明小明到达该红绿灯路段所用的时间已经超过该路段原本的倒计时,
                *   则应该切换灯以及更新倒计时并更新灯的倒计时。
                * */
                while ((cpSum -= this.lightTime) > 0) {
                    if (this.lightColor == 1) {
                        this.lightColor = 3;
                        this.lightTime = LightNode.G;
                    }else if (this.lightColor == 3) {
                        this.lightColor = 2;
                        this.lightTime = LightNode.Y;
                    }else if (this.lightColor == 2) {
                        this.lightColor = 1;
                        this.lightTime = LightNode.R;
                    }
                }

                // 因为while语句执行判断之后cpSum -= this.lightTime最后会被多执行一次,所以这里要加回来
                // 如果cpSum还有剩余的时间但不超过总倒计时 则该路段的灯的现倒计时应该减去cpSum
                if ((cpSum += this.lightTime) > 0) {
                    this.lightTime -= cpSum;
                }

                // 最后如果是红灯 则需等待lightTime秒
                if (this.lightColor == 1) {
                    sum += lightTime;
                }
                // 最后如果是黄灯,则需等待lightTime秒 + 一段红灯的完整倒计时
                else if (this.lightColor == 2) {
                    sum += lightTime + LightNode.R;
                }

            }

            // 返回回家已用时长
            return sum;
        }
    }
}

### CCF CSP Java 考试备考资料与认证信息 #### 关于CCF CSP认证 中国计算机学会推出的CCF CSP认证旨在评估软件开发者的实际编程能力,每年分别在3月、9月和12月举行三次认证考试[^1]。 #### 编程语言的选择 对于希望使用Java参加CCF CSP认证的考生,在报名时可以选择ALL作为考试语言选项。这意味着可以在不同的题目中自由选择包括但不限于Java在内的多种编程语言来解答问题[^3]。 #### 准备材料推荐 为了更好地准备基于JavaCCF CSP认证: - **官方资源**:定期访问官方网站获取最新的公告和技术文档更新;利用官网提供的历年真题进行实战演练。 - **书籍** - *《算法导论》*:深入理解数据结构和经典算法设计原理。 - *《Effective Java》*:掌握高效编写高质量Java程序的最佳实践指南。 - **在线课程平台** - LeetCode, Codeforces等网站提供了丰富的竞赛级编程挑战,有助于提高解题速度和准确性。 - Coursera上的专项课程如“Algorithms Specialization”,能够帮助巩固理论基础并学习更多高级主题。 - **模拟环境搭建** 使用本地集成开发环境(IDE),比如IntelliJ IDEA Ultimate Edition 或 Eclipse IDE for Java Developers 来熟悉真实的编码场景,并确保所写的代码能够在标准Java运行环境中正常工作。 ```java // 示例:简单的HelloWorld.java文件用于验证编译器配置是否正确 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值