第六届蓝桥杯java B组决赛真题详解

第六届蓝桥杯java B组决赛真题详解

1、分机号

X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位。比如:

751,520,321 都满足要求,而,
766,918,201 就不符合要求。

现在请你计算一下,按照这样的规定,一共有多少个可用的3位分机号码?

请直接提交该数字,不要填写任何多余的内容。

思路:

这道题的解题方法很简单,根据题目的要求,枚举每一个三位数进行检查就可以解决问题
枚举+检查

public class question1 {
	static int ans=0;
	public static void main(String args[]) {
		int ans=0;
		//根据题目要求,三位不重复的数,且依次递减,因为范围很小,我们可以直接枚举在这个区间的每一个数,最小值是210,最大值应该为987
		for(int i=210;i<=987;i++) {
			int num=i;
			int a,b,c;
			a=num%10;					//第三位数字
			b=num/10%10;				//第二位数字
			c=num/100;					//第一位数字
			//判断当前分机号的三位数字依次递减且不存在重复数字
			if(a<b&&b<c&&a!=c)		
				ans++;			
		}
		System.out.println(ans);
	}	
}
最终答案:120

2、五星填数

如【图1.png】的五星图案节点填上数字:1~12,除去7和11。
要求每条直线上数字和相等。

如图就是恰当的填法。

请你利用计算机搜索所有可能的填法有多少种。
注意:旋转或镜像后相同的算同一种填法。

请提交表示方案数目的整数,不要填写任何其它内容。

图1.jpg
图2.jpg
思路:解题思路在代码的注释里面

全排列+检查+回溯

/*
 解题思路
 这道题可以变成对1,2,3,4,5,6,8,9,10,12几个数字进行全排列
 然后检查每种排列是否满足要求,满足要求就将填发增加1
 因为旋转或镜像后相同的算作同一种方法,可以每种填发可以经过旋转可以有5种形式,经过镜像之后有5中形式
 将最后算的的结果除以10就是最终的答案
 */
public class question2 {
	static int count=0;
	public static void main(String args[]) {
		int[] a= {1,2,3,4,5,6,8,9,10,12};
		f(a,0,a.length-1);
		System.out.println("ans="+count/10);	//满足条件的全排列的数量除以10,就是本题的结果
	}

	
	private static void f(int[] a, int start, int end) {
		if(start==end) {			//全排列完成,检查排列的结果,如果满足要求就将解法加一
			if(check(a))
				count++;
		}
		
		//将当前位后面的每一位都和当前的这一位数字发生交换,完成全排列
		for (int i = start; i <= end; i++) {
			swap(a,i,start);			//交换
			f(a, start+1, end);
			swap(a,i,start);			//回溯,将这次循环中的交换恢复,保证数组的内容不发生变化
		}
		
	}

	//检查排列结果,即对每一条边上的值求和,判断各条边是否相等
	private static boolean check(int[] a) {
		int x=a[1]+a[4]+a[5]+a[6];
		int y=a[1]+a[3]+a[7]+a[8];
		int z=a[2]+a[4]+a[8]+a[9];
		int h=a[0]+a[3]+a[5]+a[9];
		int m=a[0]+a[2]+a[6]+a[7];
		if(x==y&&x==z&&x==h&&x==m)
			return true;
		return false;
	}

	//交换数组中的两个指定下标的元素
	private static void swap(int[] a, int i, int start) {
		int b=a[i];
		a[i]=a[start];
		a[start]=b;		
	}
}
最终答案:12

3、显示二叉树(代码填空)

题目


标题:显示二叉树

排序二叉树的特征是:
某个节点的左子树的所有节点值都不大于本节点值。
某个节点的右子树的所有节点值都不小于本节点值。

为了能形象地观察二叉树的建立过程,小明写了一段程序来显示出二叉树的结构来。


class BiTree
{
	private int v;
	private BiTree l;
	private BiTree r;
	
	public BiTree(int v){
		this.v = v;
	}
	
	public void add(BiTree the){
		if(the.v < v){
			if(l==null) l = the;
			else l.add(the);
		}
		else{
			if(r==null) r = the;
			else r.add(the);
		}
	}
	
	public int getHeight(){
		int h = 2;
		int hl = l==null? 0 : l.getHeight();
		int hr = r==null? 0 : r.getHeight();
		return h + Math.max(hl,hr);
	}
	
	public int getWidth(){
		int w = (""+v).length();
		if(l!=null) w += l.getWidth();
		if(r!=null) w += r.getWidth();
		return w;
	}
	
	public void show(){
		char[][] buf = new char[getHeight()][getWidth()];
		printInBuf(buf, 0, 0);
		showBuf(buf);
	}
	
	private void showBuf(char[][] x){
		for(int i=0; i<x.length; i++){
			for(int j=0; j<x[i].length; j++)
				System.out.print(x[i][j]==0? ' ':x[i][j]);
			System.out.println();
		}
	}
	
	private void printInBuf(char[][] buf, int x, int y){
		String sv = "" + v;
		
		int p1 = l==null? x : l.getRootPos(x);
		int p2 = getRootPos(x);
		int p3 = r==null? p2 : r.getRootPos(p2+sv.length());
		
		buf[y][p2] = '|';
		for(int i=p1; i<=p3; i++) buf[y+1][i]='-';
		for(int i=0; i<sv.length(); i++) ________________________________;  //填空位置
		if(p1<p2) buf[y+1][p1] = '/';
		if(p3>p2) buf[y+1][p3] = '\\';
		
		if(l!=null) l.printInBuf(buf,x,y+2);
		if(r!=null) r.printInBuf(buf,p2+sv.length(),y+2);
	}
	
	private int getRootPos(int x){
		return l==null? x : x + l.getWidth();
	}
}

public class Main
{
	public static void main(String[] args)
	{		
		BiTree tree = new BiTree(500);
		tree.add(new BiTree(200));
		tree.add(new BiTree(509));
		tree.add(new BiTree(100));
		tree.add(new BiTree(250));
		tree.add(new BiTree(507));
		tree.add(new BiTree(600));
		tree.add(new BiTree(650));
		tree.add(new BiTree(450));
		tree.add(new BiTree(510));
		tree.add(new BiTree(440));
		tree.add(new BiTree(220));		
		tree.show();		
	}
}

对于上边的测试数据,应该显示出:
                  |
   /--------------500---\
   |                    |
/--200---\           /--509---\
|        |           |        |
100   /--250---\     507   /--600\
      |        |           |     |
      220   /--450         510   650
            |
            440

(如有对齐问题,请参考【图1.png】)

请分析程序逻辑,填写划线部分缺失的代码。

注意,只填写缺少的部分,不要填写已有的代码或符号,也不要加任何说明文字。
思路

对于这种代码填空的题目,完全没有必要完全看懂代码,既然只让写一行代码,那就肯定是关键的语句,可以使用Debug的方式来解决这种题目,先把要填写代码的行注释掉,然后运行这段代码,观察实际输出的结果和题目又什么差别,然后再去填写代码,基本上要填写的哪一行里就是在程序中定义过却从未使用的变量,或者是比较关键的变量,掌握这种思路求解这类问题就会很简单。

最终答案
buf[y+1][i+p2]=sv.toCharArray()[i];

4、穿越雷区

X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?

已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:

A + - + -
- + - - +
- + + + -
+ - + - +
B + - + - 

坦克车只能水平或垂直方向上移动到相邻的区。

数据格式要求:

输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
A,B都只出现一次。

要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1

例如:
用户输入:

5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

则程序应该输出:
10

资源约定:
峰值内存消耗(含虚拟机) < 512M
CPU消耗 < 2000ms

思路
基本思路:

求解在图中的最短路径问题,用到的算法大多数都是BFS(广度优先搜索),因为是广度优先搜索,所以找到的结果就是最短路径。
明确了要用到的算法,接下来问题就会变得简单很多,无非就是节点能不能走得通的判断
从起始位置进行BFS,搜索四周的几个节点,如果节点在地图范围内且可以行走(可以行走的条件是下一个节点的值和本节点不同,即题目所说的坦克必须交替穿越正能量辐射区和负能量辐射区),则在下一步走到四周的某一个可以走得通的节点,并将路径数目增加1,一直到找到B节点退出BFS,路径距离即为所求。

代码思路:

首先定义一个节点的类Node,用来存储每一个可以行走的节点,接着声明一个队列Queue,用来存储可以走的通的节点,不停执行入队和出队操作,直到当前队列为空(走不通)时结束,返回-1,或者走到B节点,返回路径长度。
因为行走过程中可能会重复走过一个节点,为了优化代码,降低时间复杂度,可以设置一个二维的布尔数组,用来标记一个节点是否被走过,若走过则不在对该节点执行入队操作

知识要点:

队列,BFS,字符串处理,节点判断,代码优化

代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class question4 {
	//字符数组,用来存储地图
	static char[][] array;
	static int n;
	public static void main(String args[]) {
		Scanner in=new Scanner(System.in);
		//对用户输入进行处理,此处不做解析
		n=in.nextInt();
		array=new char[n][n];
		String s="";
		in.nextLine();
		for (int i = 0; i < n; i++) {
			s=in.nextLine().replaceAll(" ", "");
			for (int j = 0; j < n; j++) {
				array[i][j]= s.toCharArray()[j];
			}
		}
		
		int x=0,y=0;
		//查找A节点,即起始位置,从该处开始执行BFS
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if(array[i][j]=='A') {
					x=i;y=j;
				}
			}
			if(x!=0)
				break;
		}
		//实例化一个节点,从此处开始查找
		Node node=new Node(x, y, 'A', 0);
		System.out.println(f(node));

		
	}
	private static int f(Node node) {
		Queue<Node> q=new LinkedList<Node>();			//声明一个队列,存储当前可以走的通的节点
		q.add(node);									//起始节点入队
		boolean[][] flag=new boolean[n][n];				//标志数组,标记每一个节点是否被走过
		int[] x= {1,0,-1,0};
		int[] y= {0,1,0,-1};
		while (!q.isEmpty()) {				//如果队列非空
			Node now=q.peek();				//取出队头节点
			flag[now.x][now.y]=true;		//标记该节点已经被访问过了
			q.remove();						//移除已经访问过的节点
			for(int i=0;i<4;i++) {					//遍历当前节点的四周节点
				//遍历当前节点的四周的每个节点
				//得到当前节点的下一个节点的位置和属性
				int next_x=now.x+x[i];
				int next_y=now.y+y[i];
				if(next_x<0||next_x>=n||next_y<0||next_y>=n)		//如果这个节点不在地图范围内,直接退出,寻找下一个相邻节点
					continue;
				char next_value=array[next_x][next_y];
				int next_step=now.step+1;
				if(next_value=='B')							//如果这个节点是B,返回路径长度
					return next_step;
				if(now.value!=next_value&&flag[next_x][next_y]==false)		//当前节点和下一个节点不同(交替穿越正负能量区),且下一个节点没有没有访问过,将其加入队尾
				{
					Node next=new Node(next_x, next_y, next_value, next_step);
					q.add(next);
				}
			}
			
		}
		//如果走不通,返回-1
		return -1;		
	} 
}

//节点类,标记图中的每一个节点
class Node{
	int x;			//节点的x坐标
	int y;			//节点的y坐标
	char value;		//节点的值
	int  step;		//到达该节点的最短路径长度
	
	public Node(int x, int y, char value, int step) {
		super();
		this.x = x;
		this.y = y;
		this.value = value;
		this.step = step;
	}
}

5、表格计算

某次无聊中, atm 发现了一个很老的程序。这个程序的功能类似于 Excel ,它对一个表格进行操作。
不妨设表格有 n 行,每行有 m 个格子。
每个格子的内容可以是一个正整数,也可以是一个公式。
公式包括三种:

  1. SUM(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的和。
  2. AVG(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的平均数。
  3. STD(x1,y1:x2,y2) 表示求左上角是第 x1 行第 y1 个格子,右下角是第 x2 行第 y2 个格子这个矩形内所有格子的值的标准差。

标准差即为方差的平方根。
方差就是:每个数据与平均值的差的平方的平均值,用来衡量单个数据离开平均数的程度。

公式都不会出现嵌套。

如果这个格子内是一个数,则这个格子的值等于这个数,否则这个格子的值等于格子公式求值结果。

输入这个表格后,程序会输出每个格子的值。atm 觉得这个程序很好玩,他也想实现一下这个程序。

「输入格式」
第一行两个数 n, m 。
接下来 n 行输入一个表格。每行 m 个由空格隔开的字符串,分别表示对应格子的内容。
输入保证不会出现循环依赖的情况,即不会出现两个格子 a 和 b 使得 a 的值依赖 b 的值且 b 的值依赖 a 的值。

「输出格式」
输出一个表格,共 n 行,每行 m 个保留两位小数的实数。
数据保证不会有格子的值超过 1e6 。

「样例输入」
3 2
1 SUM(2,1:3,1)
2 AVG(1,1:1,2)
SUM(1,1:2,1) STD(1,1:2,2)

「样例输出」
1.00 5.00
2.00 3.00
3.00 1.48

「数据范围」
对于 30% 的数据,满足: n, m <= 5
对于 100% 的数据,满足: n, m <= 50

资源约定:
峰值内存消耗(含虚拟机) < 512M
CPU消耗 < 2000ms

思路:

递归求解每一个公式的结果。

声明一个double的二维数组存放格子的数字,声明一个String二维数组存放用书输入每一个格子的内容,声明一个boolean二维数标记每一个格子是公式还是数值。

对于是公式的格子,根据公式类型调用对应的函数求解,因为平均值和方差都需要用到求和公式,所以只需在求和函数sum()里面进行递归操作,详细操作参考程序代码,本题不做详细解释。

本题需要定义5个方法

 static void f(int i, int j)							//求解一个公式的格子,将结果赋给存放数值的数组,并将格子标记为是一个数字
 double sum(int x1,int y1,int x2,int y2)				//求解(x1,y1,x2,y2)范围内的和
 static double avg(int x1,int y1,int x2,int y2) 		//求解(x1,y1,x2,y2)范围内的平均数
 double std(int x1,int y1,int x2,int y2)				//求解(x1,y1,x2,y2)范围内的标准差
 boolean check(String s)								//检查一个字符串是不是公式,如果是返回true,不是返回false
源码
import java.io.StreamCorruptedException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class question5 {
	static int n,m;
	static String[][] str;
	static double[][] array;
	static boolean[][] flag;
	public static void main(String args[]) {
		//首先解决输入问题
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		str=new String[n][m];
		array=new double[n][m];
		flag=new boolean[n][m];
		in.nextLine();		//将剩余的空行读出,开始接收数据
		for (int i = 0; i < n; i++) {
			String[] s=in.nextLine().split(" ");
			for (int j = 0; j < m; j++) {
				str[i][j]=s[j];
			}
		}
		
		//输入问题已解决,开始进行数据的转换,首先进行初始数据的转换,就是用户刚开始输入的内容
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if(check(str[i][j]))
					continue;
				flag[i][j]=true;
				array[i][j]=Double.parseDouble(str[i][j]);
			}
		}
		
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if(!flag[i][j]) {		//如果当前的这个格子不是数字,进行转换
					f(i,j);
				}
			}
		}
		
		
		//数据转换已完成,开始向外输出数据
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				System.out.printf("%.2f\t",array[i][j]);
			}
			System.out.println();
		}
	}
	
	
	 private static void f(int i, int j) {
		double ans=0;
		String[] value=((String) str[i][j].subSequence(4, str[i][j].length()-1)).split(":");		//将里面的四个值提取出来
		int x1=Integer.parseInt(value[0].split(",")[0]);
		int y1=Integer.parseInt(value[0].split(",")[1]);
		int x2=Integer.parseInt(value[1].split(",")[0]);
		int y2=Integer.parseInt(value[1].split(",")[1]);
		
		if(((String)str[i][j].subSequence(0, 3)).equals("SUM"))
			ans=sum(x1,y1,x2,y2);
		if(((String)str[i][j].subSequence(0, 3)).equals("AVG"))
			ans=avg(x1,y1,x2,y2);
		if(((String)str[i][j].subSequence(0, 3)).equals("STD"))
			ans=std(x1,y1,x2,y2);
		array[i][j]=ans;
		flag[i][j]=true;
	}


	//这三个函数是三个公式
	static double sum(int x1,int y1,int x2,int y2) {
		double sum=0;
		for (int i = x1-1; i < x2; i++) {
			for (int j = y1-1; j < y2; j++) {
				if(!flag[i][j])
					f(i, j);
				sum+=array[i][j];
			}		
		}
		return sum;
	}
	
	static double avg(int x1,int y1,int x2,int y2) {
		double sum=0;
		sum=sum(x1, y1, x2, y2);
		int count=(x2-x1+1)*(y2-y1+1);
		sum=sum/count;
		return sum;
	}
	
	static double std(int x1,int y1,int x2,int y2) {
		double avg=avg(x1, y1, x2, y2);
		double sum=0;
		int count=(x2-x1+1)*(y2-y1+1);
		for (int i = x1-1; i < x2; i++) {
			for (int j = y1-1; j < y2; j++) {
				sum+=Math.pow((array[i][j]-avg), 2);				
			}			
		}
		sum=sum/count;		//方差
		sum=Math.sqrt(sum);	//标准差
		return sum;
	}
	
	//检查一个字符串是不是公式,如果是返回true,不是返回false
	static boolean check(String s) {
		char c=s.toCharArray()[0];
		if(c>60)
			return true;
		else
			return false;
	}
	
}


/*
样例输入
3 2
1 SUM(2,1:3,1)
2 AVG(1,1:1,2)
SUM(1,1:2,1) STD(1,1:2,2)

样例输出
1.00 5.00
2.00 3.00
3.00 1.48
 */


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值