题目背景
汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。
问题描述
一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。上学
输入格式
输入的第一行包含空格分隔的三个正整数 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;
}
}
}


7303

被折叠的 条评论
为什么被折叠?



