目录
201312-2:ISBN号码
201403-2:窗口
201409-2:画图
201412-2:Z字型扫描
201503-2:数字排序
201509-2:日期计算
201512-2:消除类游戏
201604-2:俄罗斯方块
201609-2:火车购票
201612-2:工资计算
201703-2:学生排队
201709-2:公共钥匙盒
201712-2:游戏
201803-2:碰撞的小球
201809-2:买菜
201812-2:小明放学
201903-2:二十四点
思路:
1.这题主要考察字符串中的单个字符处理
2.判断非‘-’号时的数字递进乘积即可
3.Char中的数字字符与int数字转换:减去字符‘0’即可
4.注意输出时接的为String的“X”(双引号),而不是Char的‘X’(单引号)
import java.util.Scanner;public class CSP201312_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String ISBN = sc.next();int sum = 0;for(int i = 0, j = 1; i < 11; i++) {if(ISBN.charAt(i) != '-') {sum += (ISBN.charAt(i) - '0') * j;j++;}}int idCode = sum % 11;if((idCode == 10 && ISBN.charAt(12) == 'X') || idCode == ISBN.charAt(12) - '0') {System.out.println("Right");}else {System.out.println(ISBN.substring(0, 12) + (idCode == 10 ? "X" : idCode)); //注意输出时接的为String的“X”(双引号),而不是Char的‘X’(单引号)}}
}
思路:
1.采用链表方便删除中间结点并添加该结点到最后(移动被点击窗口到最前面)
2.点击时注意点击到窗口边界上情况
import java.util.Scanner;
import java.util.LinkedList;class Window {int id = 0;int x1 = 0;int y1 = 0;int x2 = 0;int y2 = 0;
}public class CSP201403_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();LinkedList wl = new LinkedList();int[][] click = new int[m][2];for(int i = 1; i <= n; i++) {Window w = new Window(); w.id = i;w.x1 = sc.nextInt();w.y1 = sc.nextInt();w.x2 = sc.nextInt();w.y2 = sc.nextInt();wl.add(w);}for(int i = 0; i < m; i++) {for(int j = 0; j < 2; j++) {click[i][j] = sc.nextInt();}}Window temp = new Window();for(int i = 0; i < m; i++) {int flag = 0;for(int j = n - 1; j >= 0; j--) {if(click[i][0] >= wl.get(j).x1 && click[i][0] <= wl.get(j).x2 && click[i][1] >= wl.get(j).y1 && click[i][1] <= wl.get(j).y2) {System.out.println(wl.get(j).id);temp = wl.get(j);wl.remove(j);wl.addLast(temp);flag = 1;break;}}if(flag == 0) {System.out.println("IGNORED");}}}
}
思路:
1.建立二维数组作为整个坐标系,数组中的值默认为0,0代表没涂色,1代表已涂色
2.输入的左下角的坐标作为循环的起点,右上角的坐标作为循环的终点
3.每次循环时,检查位置是否已经涂色,若位置状态为0,则将位置状态设置为1,计数器加1(代表涂色面积加1),最后输出计数器的值即为涂色的面积。
import java.util.Scanner;public class CSP201409_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int[][] coordinate = new int[101][101];int n = sc.nextInt();int[][] rectangle = new int[n][4];int sum = 0;for(int i = 0; i < n; i++) {for(int j = 0; j < 4; j++) {rectangle[i][j] = sc.nextInt();}for(int x = rectangle[i][0]; x < rectangle[i][2]; x++) {for(int y = rectangle[i][1]; y < rectangle[i][3]; y++) {if(coordinate[x][y] == 0) {coordinate[x][y] = 1;sum++;}}}}System.out.println(sum);}
}
方法一思路:
1.采用两个代表横纵坐标的双指针来控制坐标位置
2.观察到扫描方向有四种:右→、左下↙、下↓、右上↗
3.观察到方向转换有10种:右-左下、右-右上;
左下-下、左下-左下、左下-右;
下-右上、下-左下;
右上-右上、右上-右、右上-下;
4.根据观察,分为四种情况来改变坐标指针,每种情况又根据自身方向转换情况调整下一次的方向
import java.util.Scanner;public class CSP201412_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[][] rectangle = new int[n][n];for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {rectangle[i][j] = sc.nextInt();}}int row = 0;int col = 0;String direction = "right";while(row >= 0 && row < n && col >= 0 && col < n) {System.out.print(rectangle[row][col] + " ");switch (direction) {case "right":col++;if(row == 0) {direction = "leftDown";}else {direction = "rightUp";}break;case "leftDown":row++;col--;if(col == 0 && row != n-1) {direction = "down";}else if(row == n-1) {direction = "right";}else {direction = "leftDown";}break;case "down":row++;if(col == 0) {direction = "rightUp";}else {direction = "leftDown";}break;case "rightUp":row--;col++;if(row == 0 && col != n-1) {direction = "right";}else if(col == n-1) {direction = "down";}else {direction = "rightUp";}break;}}}
}
方法二思路:
1.采用两个代表横纵坐标的双指针来控制坐标位置
2.每个对角线上的横纵坐标索引和恒为一个常数,用一个对角线行数索引表示
3.每次走一个对角线,偶数索引对角线移动方向为右上,每次移动行-1,列+1;奇数索引对角线移动方向为左下,每次移动行+1,列-1
4.每次变线时对角线索引始终不能超过n-1,在上半部分时为索引本身,在下半部分为n-1
import java.util.Scanner;public class CSP201412_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[][] rectangle = new int[n][n];for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {rectangle[i][j] = sc.nextInt();}}int row = 0;int col = 0;int diagonal = row + col; //对角线行数索引:对角线上的行索引加列索引的和恒为一个常数,可理解为对角线行数的索引while(diagonal < 2*n-1) {if(diagonal % 2 == 0) {row = diagonal > n-1 ? n-1 : diagonal; //每次变线时对角线索引始终不能超过n-1,在上半部分时为索引本身,在下半部分为n-1col = diagonal - row;for (; col <= diagonal && col < n; col++, row--) //偶数索引对角线移动方向为右上,每次移动行-1,列+1{System.out.print(rectangle[row][col] + " ");}}else {col = diagonal > n - 1 ? n - 1 : diagonal;row = diagonal - col;for (; row <= diagonal && row < n; row++, col--) //奇数索引对角线移动方向为左下,每次移动行+1,列-1{System.out.print(rectangle[row][col] + " ");}}diagonal++;}}
}
思路:
1.用一个数组存储输入的数的次数,索引为输入的数
2.遍历数组,找出数组里的最大值,输出索引和次数,然后将该索引的次数置为0,当最大值为0时,终止循环。
import java.util.Scanner;public class CSP201503_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] sum = new int[1001];for(int i = 0; i < n; i++) {sum[sc.nextInt()]++;}int max = -1; while(max != 0) {max = 0;int index = -1;for(int j = 0; j < 1001; j++) {if(sum[j] > max) {max = sum[j];index = j;}}if(index != -1) {System.out.println(index + " " + max);sum[index] = 0;}}}
}
思路:
1.先判断是闰年还是平年,然后创建相应的月份数组
2.然后一个月一个月地进行判断和推进
import java.util.Scanner;public class CSP201509_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int year = sc.nextInt();int days = sc.nextInt();int[] months = new int[]{31,28,31,30,31,30,31,31,30,31,30,31};if(year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {months[1] = 29; }int month = 1;int day = 0;int i = 0;while(days > 0) {if(days > months[i]) {month++;}else{day = days;}days -= months[i];i++;}System.out.println(month);System.out.println(day);}
}
思路:
1.用一个二维数组存放输入的矩阵,用另一个二维数组存放消除后的矩阵
2.行列分别进行消除,遍历数组,当有三个连续相同的数则全置为0
import java.util.Scanner;public class CSP201512_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();int[][] input = new int[n][m];int[][] out = new int[n][m];for(int i = 0; i < n; i++) {for(int j = 0; j < m; j++) {input[i][j] = sc.nextInt();out[i][j] = input[i][j];}}for(int i = 0; i < n; i++) {for(int j = 0; j < m; j++) {//行消除if(j
思路:
0.根据题目可知,所有0的位置不用考虑,且仅考虑方块下落的四列即可
1.找出方块下落所移动的距离,即方块所有列单独可移动的最短距离
2.找出方块中每一列的最下面一个1的位置,即该列的上界
3.找出方格图中每一列最上面一个1的位置,即该列的下界
4.下界减去上界为两个1之间的距离,该距离再减去1即该列的方块可以移动的距离,计算每列的移动距离后找出最短的移动距离,即方块下落所能移动的距离
5.将方块中为1的数移动上面所求最小距离后填入方格图中
import java.util.Scanner;public class CSP201604_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int[][] rectangle = new int[15][10];int[][] patch = new int[4][4];for(int i = 0; i < 15; i++) {for(int j = 0; j < 10; j++) {rectangle[i][j] = sc.nextInt();}}for(int i = 0; i < 4; i++) {for(int j = 0; j < 4; j++) {patch[i][j] = sc.nextInt();}}int location = sc.nextInt();location--;//找出方块下落所移动的距离,即方块所有列单独可移动的最短距离int minDistance = 16;for(int column = 0; column < 4; column++) {//找该列的上界int upEdge = -1;for(int row = 0; row < 4; row++) {if(patch[row][column] == 1) {upEdge = row;}}if(upEdge == -1) {continue;}//找该列的下界int downEdge = 15;for(int row = 14; row > 3; row--) {if(rectangle[row][column + location] == 1) {downEdge = row;}}minDistance = downEdge-upEdge < minDistance ? downEdge-upEdge : minDistance;}//移动方块for(int row = 0; row < 4; row++) {for(int column = 0; column < 4; column++) {if(patch[row][column] == 1) {rectangle[row + (minDistance-1)][column +location] = 1;}}}for(int i = 0; i < 15; i++) {for(int j = 0; j < 10; j++) {System.out.print(rectangle[i][j] + " ");}System.out.println();}}
}
方法一思路:
1.座位没卖出前标记为0,卖出后标记为1
2.先按连续座位需求检索,检索每一排是否有可满足的连续座位,有则分配
3.若全部检索完没有满足连续的座位,则插空安排座位,但凡座位为0就给分配
4.判断每一排连续座位时采用正向双指针,逐行检测是否满足当前连续购票需求
import java.util.Scanner;public class CSP201609_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] arrN = new int[n];int[][] location = new int[20][5];for(int i = 0; i < n; i++) {arrN[i] = sc.nextInt();int buyFlag = 0;for(int row = 0; row < 20; row++) {int pointOne = 0;int pointTwo = 0;while(pointTwo < 5) {int conSpace = 0;while(pointOne < 5 && location[row][pointOne] != 0) {pointOne++;}pointTwo = pointOne;while(pointTwo < 5 && location[row][pointTwo] == 0) {conSpace++;pointTwo++;}if(conSpace >= arrN[i]) {for(int buyTicket = 0; buyTicket < arrN[i]; buyTicket++) {location[row][pointOne] = 1;System.out.print((row*5+pointOne+1)+" ");pointOne++;}buyFlag = 1;break;}pointOne = pointTwo;}if(buyFlag == 1) {break;}}if(buyFlag == 0) {int buyTicket = 0;for(int row = 0; row < 20; row++) {for(int column = 0; column < 5; column++) {while(location[row][column]==0 && buyTicket
方法二思路:
1.采用LinkedList实现队列,每个队列里的值存储每个位置的号
2.因为每一行总是从第一个空位开始往后安排,所以每次安排时将队列中的顶部的值返回后将其删除即可
import java.util.Scanner;
import java.util.LinkedList;public class CSP201609_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] arrN = new int[n];LinkedList[] queue = new LinkedList[20];for(int i = 0; i < queue.length; i++) {queue[i] = new LinkedList();for(int j = 0; j < 5; j++) {queue[i].add(i*5+j+1); //存储的值为每个位置的号}}for(int i = 0; i < n; i++) {arrN[i] = sc.nextInt();int buyFlag = 0; for(int row = 0; row < queue.length; row++) {if(queue[row].size() >= arrN[i]) {for(int buyTicket = 0; buyTicket < arrN[i]; buyTicket++) {System.out.print(queue[row].pop() + " ");}buyFlag = 1;break;}}if(buyFlag == 0) {int buyTicket = 0;for(int row = 0; row < queue.length; row++) {while(queue[row].size() != 0 && buyTicket < arrN[i]) {System.out.print(queue[row].pop() + " ");buyTicket++;}if(buyTicket == arrN[i]) {break;}}}System.out.println();}}
}
方法一思路:(正向求解:根据税前求税后)
1.先判断税后收入是否大于3500,不大于则税前收入等于税后收入,大于则计算需要缴多少税
2.根据题意税前工资为一个整百的数,所以根据税后工资依次加一百计算缴纳的税,当税前工资-缴纳的税=税后工资时,输出税前工资
import java.util.Scanner;public class CSP201612_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int T = sc.nextInt();if(T <= 3500) {System.out.println(T);}else {int S = T/100*100;while(true) {S += 100;int tax = 0;int A = S - 3500;if(A <= 1500) {tax += A/100*3;}else if(A <= 4500) {tax += 1500/100*3;tax += (A-1500)/10;}else if(A <= 9000) {tax += 1500/100*3;tax += (4500-1500)/10;tax += (A-4500)/5;}else if(A <= 35000) {tax += 1500/100*3;tax += (4500-1500)/10;tax += (9000-4500)/5;tax += (A-9000)/4;}else if(A <= 55000) {tax += 1500/100*3;tax += (4500-1500)/10;tax += (9000-4500)/5;tax += (35000-9000)/4;tax += (A-35000)/10*3;}else if(A <= 80000) {tax += 1500/100*3;tax += (4500-1500)/10;tax += (9000-4500)/5;tax += (35000-9000)/4;tax += (55000-35000)/10*3;tax += (A-55000)/100*35;}else {tax += 1500/100*3;tax += (4500-1500)/10;tax += (9000-4500)/5;tax += (35000-9000)/4;tax += (55000-35000)/10*3;tax += (80000-55000)/100*35;tax += (A-80000)/100*45;}if((S-tax) == T) {System.out.println(S);break;}}}}
}
方法二思路:(反向求解:根据税后求税前)
1.根据每个税率范围的端点先计算真实税后收入的范围
2.判断输入的税后收入处于哪个范围
3.根据税后收入反推不交税前的税前收入(除以(1-税率))
备注:从编程方法上来说,一种是将工资段和税率写到程序逻辑中。这种做法修改程序比较难,逻辑也比较复杂。另外一种是查表法,通过查表来计算最后的结果。查表法的优点在于,单有关规定改变时,只需要调整表格,而不需要改变程序逻辑。难点在于比赛时不够直观,所以根据情况自行选择。该问题原始数据可以建两个表格,一是工资收入段表,二是税率表。根据这两个表可以算出收入范围表,即由实际收入得到最高税率是哪一档的表。进一步的计算就变得简单许多。
import java.util.Scanner;public class CSP201612_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int T = sc.nextInt();int[] salary = new int[]{3500, 3500+1500, 3500+4500, 3500+9000, 3500+35000, 3500+55000, 3500+80000};int[] taxRate= new int[]{3, 10, 20, 25, 30, 35, 45};int[] salaryAfterTax = new int[salary.length]; //税后收入salaryAfterTax[0] = salary[0];//计算税后收入范围for(int i = 1; i < salaryAfterTax.length; i++) {salaryAfterTax[i] = salaryAfterTax[i-1] + (salary[i] - salary[i-1]) - (salary[i] - salary[i-1])*taxRate[i-1]/100;}//判断输入的税后收入处于哪个范围int i = 0;for(i = 0; i < salaryAfterTax.length; i++) {if(T <= salaryAfterTax[i]) {break;}}int S = 0;if(i == 0) {S = T;}else{S = salary[i-1] + (T - salaryAfterTax[i-1])*100/(100-taxRate[i-1]);}System.out.println(S);}
}
思路:
1.采用LinkedList存储学生学号,然后按要求删除结点和插入结点即可
import java.util.Scanner;
import java.util.LinkedList;public class CSP201703_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();LinkedList studentId = new LinkedList();for(int i = 0; i < n; i++) {studentId.add(i+1);}int m = sc.nextInt();int[][] action = new int[m][2];for(int i = 0; i < m; i++) {for(int j = 0; j < 2; j++) {action[i][j] = sc.nextInt();}int index = studentId.indexOf(action[i][0]);studentId.remove(index);studentId.add(index + action[i][1], action[i][0]);}for(int i = 0; i < n; i++) {System.out.print(studentId.get(i) + " ");}}
}
思路:
1.以时间为循环条件,每一个时间点判断一次是否有归还钥匙或取钥匙
2.计算取钥匙的最小时间和归还钥匙的最晚时间,作为循环的起点和终点
3.同一时间点必须先归还,后取
4.归还时注意多人同时归还情况,需按钥匙编号从小到大归还,所以声明一个数组来存储多人同时归还时的钥匙编号,便于排序
5.取时随意取,不用按顺序
import java.util.Scanner;
import java.util.Arrays;public class CSP201709_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] key = new int[n];for(int i = 0; i < n; i++) {key[i] = i+1;}int k = sc.nextInt();int[][] action = new int[k][4];for(int i = 0; i < k; i++) {for(int j = 0; j < 3; j++) {action[i][j] = sc.nextInt();}action[i][3] = action[i][1]+action[i][2]; //第四位存储上完课后的时间点}int minTime = 10001; //起始时间int maxTime = 0; //终止时间for(int i = 0; i < k; i++) {minTime = action[i][1] < minTime ? action[i][1] : minTime;maxTime = action[i][3] > maxTime ? action[i][3] : maxTime;}for(int time = minTime; time <= maxTime; time++) { //以时间点为循环,每一个时间点判断一次是否有还钥匙和取钥匙//还钥匙int many = 0; //存储有几个人还钥匙for(int i = 0; i < k; i++) {if(action[i][3] == time) {many++;}}if(many != 0) {int[] returnKeys = new int[many];for(int i = 0; i < k; i++) {if(action[i][3] == time && many!=0) {returnKeys[many-1] = action[i][0];many--;}}Arrays.sort(returnKeys);for(int i = 0; i < returnKeys.length; i++) {for(int j = 0; j < n; j++) {if(key[j] == 0) {key[j] = returnKeys[i];break;}}}}//取钥匙for(int i = 0; i < k; i++) {if(action[i][1] == time) {for(int j = 0; j < n; j++) {if(key[j] == action[i][0]) {key[j] = 0;break;}}}}}//输出最终钥匙盒for(int i = 0; i < n; i++) {System.out.print(key[i] + " ");}}
}
思路:
1.采用LinkedList存储小朋友编号,然后按题意循环,遇到满足条件的就删除结点,剩余一个人时输出它的编号
2.注意删除一个结点时循环指针需要保持原位,不能向后移动
import java.util.Scanner;
import java.util.LinkedList;public class CSP201712_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int k = sc.nextInt();LinkedList circle = new LinkedList();for(int i = 1; i <= n; i++) {circle.add(i);}int count = 0;while(circle.size() > 1) {for(int i = 0; i < circle.size(); i++) {count++;if(count%k == 0 || count%10 == k) {circle.remove(i);i--; //删除一个结点时循环指针需要保持原位,不能向后移动if(circle.size() == 1) { // 在循环途中结束游戏,不加这步90分break;}}}}System.out.println(circle.pop());}
}
思路:
1.创建一个小球类,包括两个元素(位置和方向)
2.判断小球是否在两边端点,在左端点则方向向右,在右端点则方向向左
3.每个时间点按当前方向前进一格,向右则++,向左则--
4.一个时间点的小球全部移动完后判断是否产生碰撞,循环整个数组判断有没有相同的,若有则产生碰撞的两个小球方向变为各自的反方向
import java.util.Scanner;class Ball {public int location;public String direction = "right";
}public class CSP201803_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int L = sc.nextInt();int t = sc.nextInt();Ball[] ball = new Ball[n];for(int i = 0; i < n; i++) {ball[i] = new Ball();ball[i].location = sc.nextInt();}for(int i = 0; i < t; i++) {for(int j = 0; j < n; j++) {//碰到左端点则方向转为“右”if(ball[j].location == 0) {ball[j].direction = "right";}//碰到右端点则方向转为“左”if(ball[j].location == L) {ball[j].direction = "left";}//每次按当前方向前进一格if(ball[j].direction.equals("right")) {ball[j].location++;}else {ball[j].location--;}}//两球相碰时方向变为各自的反方向,循环整个数组判断有没有相同的for(int j = 0; j < n; j++) {for(int k = j+1; k < n; k++) {if(ball[j].location == ball[k].location) {if(ball[j].direction.equals("right")) {ball[j].direction = "left";ball[k].direction = "right";}else {ball[j].direction = "right";ball[k].direction = "left";}}}}}//输出最后所有小球的位置for(int i = 0; i < n; i++) {System.out.print(ball[i].location + " ");}}
}
思路:
1.用一个数组存储 H 和 W 共同装车的时间,0 表示该时间无人装车,1 表示该时间有一人装车,2 表示该时间有两人装车,有2人装车时即为可聊天时间
2.数组下标表示装车时间,但凡该时间段有人在装车,则该时间++
3.因为算的是时间段,所以注意判断一段时间时应为左闭右开区间,算了左边右边就不算了
import java.util.Scanner;public class CSP201809_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int arr[] = new int[1000001];for(int i = 0; i < 2*n; i++) {int left = sc.nextInt();int right = sc.nextInt();for(int j = left; j < right; j++) {arr[j]++;}}int sum = 0;for(int i = 0; i < 1000001; i++) {if(arr[i] == 2) {sum++;}}System.out.println(sum);}
}
思路:
1.首先注意红绿灯顺序为“红-绿-黄”,从第一题“201812-1:小明上学”的题目中可以得到。
2.红绿灯会一直循环交替变换,所以将红绿灯用一个区间表示,判断每次遇到灯时是什么灯则只需要判断当前落在哪一个区间即可,当时间太长时,红绿灯可能已经过了好几轮了,所以我们求走到红绿灯时候的状况要 %(r+g+y),每个灯的区间如下:
4.遇到路时直接加上该路段所花费时间;遇到红灯时停,需加上还剩多少秒红灯;遇到绿灯不花时间,所以直接跳过;遇到黄灯时需加上还剩多少秒黄灯并且加上一段完整的红灯时间。
5.特别注意:n 最大取值 10^5, 红绿灯时间最大取值 10^6,所以最后结果最大可能取值 10^11,超出了 int 的范围,只能使用 long 才能满分,使用 int 只能得60分。
import java.util.Scanner;public class CSP201812_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int r = sc.nextInt();int y = sc.nextInt();int g = sc.nextInt();int n = sc.nextInt();int[][] arr = new int[n][2];long time = 0; //n 最大取值 10^5, 红绿灯时间最大取值 10^6,所以最后结果最大可能取值 10^11,超出了 int 的范围,只能使用 long 才能满分,使用 int 只能得60分。for(int i = 0; i < n; i++) {for(int j = 0; j < 2; j++) {arr[i][j] = sc.nextInt();}long second = 0;/** 红绿灯会一直循环交替变换,所以将红绿灯用一个区间表示,判断每次遇到灯时是什么灯则只需要判断当前落在哪一个区间即可* 当时间太长时,红绿灯可能已经过了好几轮了,所以我们求走到红绿灯时候的状况要 %(r+g+y)*/if(arr[i][0] == 0) { //遇到路时直接加上该路段所花费时间time += arr[i][1];continue;}else if(arr[i][0] == 1) { second = (time - arr[i][1] + r) % (r + g + y);}else if(arr[i][0] == 2) { second = (time - arr[i][1]) % (r +g +y);}else if(arr[i][0] == 3) {second = (time - arr[i][1] + r + g) % (r + g +y);}if(second < r) { //遇到红灯时停,需加上还剩多少秒红灯time += r - second;}else if(second > (r+g)) { //遇到黄灯时需加上还剩多少秒黄灯并且加上一段完整的红灯时间。time += (r+g+y) - second + r;}}System.out.println(time);}
}
思路:
1.首先将第一个数存入栈中,遇到'+'号:将'+'号后面的数字存入栈,遇到'-'号:将'-'号后面的数字变为负数后存入栈,遇到'x'号:将栈顶元素弹出并和'x'号后面的数字相乘,将结果存入栈,遇到'/'号:将栈顶元素弹出并和'x'号后面的数字相除,将结果存入栈,最后将栈中的所有元素相加即为表达式的计算结果。
import java.util.Scanner;
import java.util.Stack;public class CSP201903_2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();String[] str = new String[n];Stack stack = new Stack<>();for(int i = 0; i < n; i++) {str[i] = sc.next();stack.push(str[i].charAt(0) - '0'); //栈里存入第一个数for(int j = 1; j < 7; j++) {if(str[i].charAt(j) == '+') { //遇到'+'号:将'+'号后面的数字存入栈stack.push(str[i].charAt(++j) - '0');}else if(str[i].charAt(j) == '-') { //遇到'-'号:将'-'号后面的数字变为负数后存入栈int temp = -1 * (str[i].charAt(++j) - '0');stack.push(temp);}else if(str[i].charAt(j) == 'x') { //遇到'x'号:将栈顶元素弹出并和'x'号后面的数字相乘,将结果存入栈int temp = stack.pop() * (str[i].charAt(++j) -'0');stack.push(temp);}else if(str[i].charAt(j) == '/') { //遇到'/'号:将栈顶元素弹出并和'x'号后面的数字相除,将结果存入栈int temp = stack.pop() / (str[i].charAt(++j) - '0');stack.push(temp);}}//将栈中的所有元素相加int sum = 0;while(!stack.isEmpty()) {sum += stack.pop();}if(sum == 24) {str[i] = "Yes";}else {str[i] = "No";}}for(int i = 0; i < n; i++) {System.out.println(str[i]);}}
}
下一篇:每日学术速递3.22