CCF-CSP题解 第二题(Java)

目录

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:二十四点


201312-2:ISBN号码

CCF-CSP题解 第二题(Java)_第1张图片

 思路:

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’(单引号)
		}
	}
}

201403-2:窗口

CCF-CSP题解 第二题(Java)_第2张图片

 思路:

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");
			}
		}
	}
}

201409-2:画图

CCF-CSP题解 第二题(Java)_第3张图片

思路:

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);
	}
}

201412-2:Z字型扫描

CCF-CSP题解 第二题(Java)_第4张图片

方法一思路:

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-1
				col = 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++;
		}
	}
}

201503-2:数字排序

CCF-CSP题解 第二题(Java)_第5张图片

思路:

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;
			}
		}
	}
}

201509-2:日期计算

CCF-CSP题解 第二题(Java)_第6张图片

 思路:

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);
	}
}

201512-2:消除类游戏

CCF-CSP题解 第二题(Java)_第7张图片

思路:

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

201604-2:俄罗斯方块

CCF-CSP题解 第二题(Java)_第8张图片

 思路:

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();
		}
	}
}

201609-2:火车购票

CCF-CSP题解 第二题(Java)_第9张图片

 方法一思路:

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();
		}
	}
}

201612-2:工资计算

CCF-CSP题解 第二题(Java)_第10张图片

 方法一思路:(正向求解:根据税前求税后)

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);
	}
}

201703-2:学生排队

CCF-CSP题解 第二题(Java)_第11张图片

思路:

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) + " ");
		}
	}
}

201709-2:公共钥匙盒

思路:

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] + " ");
		}
	}
}

201712-2:游戏

CCF-CSP题解 第二题(Java)_第12张图片

 思路:

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());
	}
}

201803-2:碰撞的小球

CCF-CSP题解 第二题(Java)_第13张图片

 思路:

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 + " ");
		}
	}
}

201809-2:买菜

CCF-CSP题解 第二题(Java)_第14张图片

 思路:

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);
	}
}

201812-2:小明放学

CCF-CSP题解 第二题(Java)_第15张图片

 思路:

1.首先注意红绿灯顺序为“红-绿-黄”,从第一题“201812-1:小明上学”的题目中可以得到。

2.红绿灯会一直循环交替变换,所以将红绿灯用一个区间表示,判断每次遇到灯时是什么灯则只需要判断当前落在哪一个区间即可,当时间太长时,红绿灯可能已经过了好几轮了,所以我们求走到红绿灯时候的状况要 %(r+g+y),每个灯的区间如下:

CCF-CSP题解 第二题(Java)_第16张图片

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);
	}
}

201903-2:二十四点

CCF-CSP题解 第二题(Java)_第17张图片

 思路:

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]);
		}
	}
}

你可能感兴趣的:(算法题,java,算法,CCF-CSP)