0
点赞
收藏
分享

微信扫一扫

2013年第四届蓝桥杯Java C组省赛6~10题


目录

  • ​​🍋第六题:逆波兰表达式​​
  • ​​🍊🍊题目描述​​
  • ​​🍊🍊源代码​​
  • ​​🍋第七题:核桃的数量​​
  • ​​🍊🍊题目描述​​
  • ​​🍊🍊整体思路​​
  • ​​🍊🍊源代码​​
  • ​​🍋第八题:打印十字图​​
  • ​​🍊🍊题目描述​​
  • ​​🍊🍊整体思路​​
  • ​​🍊🍊源代码​​
  • ​​🍋第九题:买不到的数目​​
  • ​​🍊🍊题目描述​​
  • ​​🍊🍊思路​​
  • ​​🍊🍊源代码​​
  • ​​🍋第十题:剪格子​​
  • ​​🍊🍊题目描述​​
  • ​​🍊🍊思路​​
  • ​​🍊🍊源代码​​
  • ​​🍊🍊代码解析​​
  • ​​🍋其他真题​​

🍋第六题:逆波兰表达式

🍊🍊题目描述

正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的,机器求解并不方便。

例如:3 + 5 * (2 + 6) - 1

而且,常常需要用括号来改变运算次序。

相反,如果使用逆波兰表达式(前缀表达式)表示,上面的算式则表示为:
- + 3 * 5 + 2 6 1
不再需要括号,机器可以用递归的方法很方便地求解。

为了简便,我们假设:

  1. 只有 + - * 三种运算符
  2. 每个运算数都是一个小于10的非负整数

下面的程序对一个逆波兰表示串进行求值。
其返回值为一个数组:其中第一元素表示求值结果,第二个元素表示它已解析的字符数。

static int[] evaluate(String x)
{
if(x.length()==0) return new int[] {0,0};

char c = x.charAt(0);//String的下标也是从0开始的
if(c>='0' && c<='9') return new int[] {c-'0',1};

int[] v1 = evaluate(x.substring(1));//从0开始数,1的话,就包含1了
int[] v2 = __________________________________________; //填空位置

int v = Integer.MAX_VALUE;
if(c=='+') v = v1[0] + v2[0];
if(c=='*') v = v1[0] * v2[0];
if(c=='-') v = v1[0] - v2[0];

return new int[] {v,1+v1[1]+v2[1]};
}

请分析代码逻辑,并推测划线处的代码,通过网页提交。
注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!

🍊🍊源代码

答案为:evaluate(x.substring(1+v1[1]))

public class Main {

static int[] evaluate(String x)
{
if(x.length()==0) return new int[] {0,0};

char c = x.charAt(0);
if(c>='0' && c<='9') return new int[] {c-'0',1};

int[] v1 = evaluate(x.substring(1));
int[] v2 = evaluate(x.substring(1+v1[1]));//__________________________________________; //填空位置

int v = Integer.MAX_VALUE;
if(c=='+') v = v1[0] + v2[0];
if(c=='*') v = v1[0] * v2[0];
if(c=='-') v = v1[0] - v2[0];

return new int[] {v,1+v1[1]+v2[1]};
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String a="-+3*5+261";
int []ans=evaluate(a);
System.out.println(ans[0]);

}


}

🍋第七题:核桃的数量

🍊🍊题目描述

小张是软件项目经理,他带领3个开发组。工期紧,今天都在加班呢。为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑)。他的要求是:

  1. 各组的核桃数量必须相同
  2. 各组内必须能平分核桃(当然是不能打碎的)
  3. 尽量提供满足1,2条件的最小数量(节约闹革命嘛)
    程序从标准输入读入:
    a b c
    a,b,c都是正整数,表示每个组正在加班的人数,用空格分开(a,b,c<30)
    程序输出:
    一个正整数,表示每袋核桃的数量。
    例如:
    用户输入:
    2 4 5
    程序输出:
    20
    再例如:
    用户输入:
    3 1 1
    程序输出:
    3
    资源约定:
    峰值内存消耗(含虚拟机) < 64M
    CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

🍊🍊整体思路

这是一道代码题。
读完题目,想到的就是暴力。

满足条件的最大值为三数之积。那么从1开始,到三数之积,能被a,b,c整除的就是答案。

🍊🍊源代码

import java.util.Scanner;

public class Main {

public static void main(String[] args) {
Scanner in =new Scanner(System.in);//输入的前提语句
int a=in.nextInt();//输入a
int b=in.nextInt();//输入b
int c=in.nextInt();//输入c

int max=a*b*c;//满足条件的最大值
for(int i=1;i<=max;i++) {//暴力
if(i%a==0&&i%b==0&&i%c==0) {//满足条件的,就是答案
System.out.println(i);//输出答案
break;//找到一个,直接停止程序
}
}
}
}

🍋第八题:打印十字图

🍊🍊题目描述

小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示(可参见图片)

2013年第四届蓝桥杯Java C组省赛6~10题_蓝桥杯


  对方同时也需要在电脑dos窗口中以字符的形式输出该标志,并能任意控制层数。

为了能准确比对空白的数量,程序要求对行中的空白以句点(.)代替。

输入格式
  一个正整数 n (n<30) 表示要求打印图形的层数

输出格式
  对应包围层数的该标志。

例如:

  用户输入:

  1

  程序应该输出:

2013年第四届蓝桥杯Java C组省赛6~10题_源文件_02

再例如:

  用户输入:

  3

  程序应该输出:

2013年第四届蓝桥杯Java C组省赛6~10题_蓝桥杯_03

请仔细观察样例,尤其要注意句点的数量和输出位置。

资源约定:
  峰值内存消耗 < 64M
  CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
  注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
  注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

🍊🍊整体思路

读完题目,实际上就是动态规划。跟之前做的打印题没什么两样,声明一个二维字符数组,满足条件的就存$,其余的就存.。之后就for循环打印出来。就是找条件会花费时间。

我们第一次做,是以n=3为例子,先进行最外层的打印。之后找到公式,把死的写成活的即可。下面直接给出答案代码

🍊🍊源代码

import java.util.Scanner;

public class Main {
static int N,R,L;
static char[][] arr;


//存储每一层
static void deal(int n) {
//n=3,总宽为17,最大下标为16
int l,r;
l=(N-n)*2;//每一层的最小下标
r=l+9+4*(n-1)-1;//最大下标
for(int i=l+2;i<=r-2;i++) {//上边界和下边界
arr[l][i]='$';
arr[r][i]='$';
}

//四角四个点
arr[l+1][l+2]='$';
arr[l+1][r-2]='$';
arr[r-1][l+2]='$';
arr[r-1][r-2]='$';

//每角三个点
for(int i=l;i<l+3;i++) {
arr[l+2][i]='$';
arr[r-2][i]='$';
}

for(int i=r;i>r-3;i--) {
arr[l+2][i]='$';
arr[r-2][i]='$';
}

for(int i=l+3;i<=r-3;i++) {
arr[i][l]='$';
arr[i][r]='$';
}
}

static void printAll() {
for(int i=0;i<=R;i++) {
for(int j=0;j<=R;j++) {
if(arr[i][j]!='$') arr[i][j]='.';
System.out.print(arr[i][j]);
}
System.out.println();
}
}

public static void main(String[] args) {
Scanner in=new Scanner(System.in);
N=in.nextInt();
R=9+4*(N-1)-1;//最大下标
arr=new char [R+1][R+1];//声明空间必须是R+1
for(int i=N;i>=1;i--) {
deal(i);
}
int c_i=2*N+2;
int c_j=2*N+2;
arr[c_i][c_j]='$';//二维数组最中间的空间
for(int i=c_i-2;i<c_i+3;i++) {//十字中的横
arr[c_i][i]='$';
}
for(int i=c_i-2;i<c_i+3;i++) {//十字中的竖
arr[i][c_j]='$';
}
printAll();//调用函数输出
}
}

🍋第九题:买不到的数目

🍊🍊题目描述

小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。

小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。

你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。

本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。

输入格式
  两个正整数,表示每种包装中糖的颗数(都不多于1000)

要求输出:
  一个正整数,表示最大不能买到的糖数

例如:
  用户输入:
  4 7
  程序应该输出:
  17

再例如:
  用户输入:
  3 5
  程序应该输出:
  7

资源约定:
  峰值内存消耗 < 64M
  CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
  注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
  注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

🍊🍊思路

看完题目,直接遍历就是了。把能买到的数目存起来,再从最大开始往小遍历,买不到的就输出。

这道题还是有公式的,直接输出a*b-a-b

🍊🍊源代码

import java.util.HashSet;
import java.util.Scanner;

public class Main {

public static void main(String[] args) {
Scanner in=new Scanner (System.in);//输入的前提语句
int a=in.nextInt();//输入a
int b=in.nextInt();//输入b
int max=a*b;//最大
HashSet <Integer> set=new HashSet<Integer>();//声明
for(int i=0;a*i<max;i++) {//遍历输出
for(int j=0;a*i+j*b<max;j++) {
set.add(a*i+b*j);//买到的就添加
}
}

for(int i=max-1;i>=0;i--) {
if(!set.contains(i)) {
System.out.println(i);
break;
}
}
}
}

import java.util.HashSet;
import java.util.Scanner;

public class Main {

public static void main(String[] args) {
Scanner in=new Scanner (System.in);//输入的前提语句
int a=in.nextInt();//输入a
int b=in.nextInt();//输入b
System.out.println(a*b-a-b);
}
}

🍋第十题:剪格子

🍊🍊题目描述

如图所示,3 x 3 的格子中填写了一些整数。

2013年第四届蓝桥杯Java C组省赛6~10题_源文件_04

我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
  如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
  如果无法分割,则输出 0

程序输入输出格式要求:
  程序先读入两个整数 m n 用空格分割 (m,n<10)
  表示表格的宽度和高度
  接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000
  程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目。

例如:
  用户输入:
  3 3
  10 1 52
  20 30 1
  1 2 3

则程序输出:
  3

再例如:
  用户输入:
  4 3
  1 1 1 1
  1 30 80 2
  1 1 1 100

则程序输出:

  10

2013年第四届蓝桥杯Java C组省赛6~10题_蓝桥杯_05

资源约定:
  峰值内存消耗 < 64M
  CPU消耗 < 5000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
  注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
  注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

🍊🍊思路

读完题目,我们想到以(0,0)为基点,进行深搜dfs,用递归实现。

在这道题里,每次走动,都有四个方向:上下左右。

最主要的就是这个,其他细节的地方具体看代码解析。

🍊🍊源代码

import java.util.Scanner;

public class Main {
static int[][]g;
static int[][]vis;
private static int n;
private static int m;
private static int total;
private static int ans=Integer.MAX_VALUE;

static void dfs(int i,int j,int steps,int sum) {
if(i<0||i==n||j<0||j==m||vis[i][j]==1) return;
if(sum==total/2) {
ans=Math.min(ans, steps);
return ;
}
if(sum>total/2) return;
vis[i][j]=1;
dfs(i-1,j,steps+1,sum+g[i][j]);
dfs(i+1,j,steps+1,sum+g[i][j]);
dfs(i,j-1,steps+1,sum+g[i][j]);
dfs(i,j+1,steps+1,sum+g[i][j]);
vis[i][j]=0;
}

public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in=new Scanner(System.in);
m=in.nextInt();
n=in.nextInt();
g=new int [n][m];
vis=new int [n][m];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
g[i][j]=in.nextInt();
total+=g[i][j];
}
}
dfs(0,0,0,0);
System.out.println(ans);
}
}

🍊🍊代码解析

4 static int[][]g;

存储输入数组

5 static int[][]vis;

存储访问过的格子

9 private static int ans=Integer.MAX_VALUE;

让ans初始化为一个大数

4~9

这些都是全局变量,在各个函数里面都可以用到

29~30
注意m是列,n才是行

31~32
g=new int [n][m];
vis=new int [n][m];

必须得要初始化才行

32~38

输入存储,并且得到总值total

12 if(i<0||in||j<0||jm||vis[i][j]==1) return;

这是边界条件

12 if(i<0||in||j<0||jm||vis[i][j]==1) return;

边界条件:
下标溢出,以及访问重复

14 ans=Math.min(ans, steps);

取得多个答案较小值

第18行 vis[i][j]=1;

访问过的,进行标记

23 vis[i][j]=0;//走完一个循环,重置

回溯,清零

举报

相关推荐

0 条评论