蓝桥杯☆☆难度题目(8,9题)

来源:互联网 发布:董事长助理面试 知乎 编辑:程序博客网 时间:2024/05/17 06:49
 1.机器人行走
某少年宫引进了一批机器人小车。可以接受预先输入的指令,按指令行动。小车的基本动作很简单,只有3种:左转(记为L),右转(记为R),向前走若干厘米(直接记数字)。

例如,我们可以对小车输入如下的指令:15L10R5LRR10R20 则,小车先直行15厘米,左转,再走10厘米,再右转,…
不难看出,对于此指令串,小车又回到了出发地。
你的任务是:编写程序,由用户输入指令,程序输出每条指令执行后小车位置与指令执行前小车位置的直线距离。

输入、输出格式要求
用户先输入一个整数n(n<100),表示接下来将有n条指令。接下来输入n条指令。每条指令只由L、R和数字组成(数字是0~100之间的整数),每条指令的长度不超过256个字符。
程序则输出n行结果。每条结果表示小车执行相应的指令前后位置的直线距离。要求四舍五入到小数后2位。 例如:用户输入:
5
L100R50R10
3LLL5RR4L12
LL
100R
5L5L5L5

则程序输出:
102.96
9.06
0.00
100.00
0.00

题目分析:
1.首先要解决位置问题,定义xy全局变量
2.方向问题,使用xy两个数组
3.输入问题,最后用input.nextLine结尾
4.判断是不是数字,是的话把步数存起来,连续数字用*10累加
5.对步数对应方向进行行走,注意初始化步数,根据字符改变方向,注意%适配数组范围
6.输出保留两位数字,初始化x,y的值

     int step=0;
     int point=0;
     for (int i = 0; i < st.length(); i++) {
          char one=st.charAt(i);
          if(one>='0'&&one<='9'){
              step=step*10+one-'0';
          }else{
              x=x+step*px[point];
              y=y+step*py[point];
              step=0;
              if(one=='L'){
                   point=(point+3)%4;
              }else{
                   point=(point+1)%4;
              }
          }
     }
     System.out.println(new DecimalFormat("0.00").format(Math.sqrt(x*x+y*y)));
     x=0;
     y=0;
注意事项:添加一个方向改变以致行走
2.兰顿蚂蚁
    兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种。
    平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只“蚂蚁”。
    蚂蚁的头部朝向为:上下左右其中一方。
    蚂蚁的移动规则十分简单:
    若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格;
    若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
    规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,蚂蚁经过漫长的混乱活动后,会开辟出一条规则的“高速公路”。
    蚂蚁的路线是很难事先预测的。
    你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第n步行走后所处的位置。

【数据格式】
输入数据的第一行是 m n 两个整数(3 < m, n < 100),表示正方形格子的行数和列数。
接下来是 m 行数据。
每行数据为 n 个被空格分开的数字。0 表示白格,1 表示黑格。
接下来是一行数据:x y s k, 其中x y为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从0开始编号)。s 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:UDLR表示。k 表示蚂蚁走的步数。
输出数据为两个空格分开的整数 p q, 分别表示蚂蚁在k步后,所处格子的行号和列号。

例如, 输入:
5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5
程序应该输出:
1 3

再例如, 输入:
3 3
0 0 0
1 1 1
1 1 1
1 1 U 6
程序应该输出:
0 0

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

题目分析:
1.通过输入确定数组容量,位置和方向通过对象确定
2.做步数的for循环
3.按照顺序改变方向,格子颜色,位置

... for (int i = 0; i < step; i++) {
          if(arr[ant.x][ant.y]==0){
              ant.point=(ant.point+3)%4;
              arr[ant.x][ant.y]=1;
          }else{
              ant.point=(ant.point+1)%4;
              arr[ant.x][ant.y]=0;
          }

          if(ant.point==0){
              ant.x--;
          }else if(ant.point==1){
              ant.y++;
          }else if(ant.point==2){
              ant.x++;
          }else{
              ant.y--;
          }
     }...

注意事项:
1.x为几行,自上向下递增
2.对每个方向进行循环行走

3.加法变乘法
我们都知道:1+2+3+ ... + 49 = 1225
现在要求你把其中两个不相邻的加号变成乘号,使得结果为2015
比如:
1+2+3+...+10*11+12+...+27*28+29+...+49 = 2015
就是符合要求的答案。
请你寻找另外一个可能的答案,并把位置靠前的那个乘号左边的数字提交(对于示例,就是提交10)。

题目分析:
1.看清题意,这里要修改的是两个不相邻的符号
2.所以先用for确定第一个符号的位置,然后用第二个for确定符合的位置
     for (int i = 1; i < 30; i++) {
          for (int j = i; j < 30; j++) {
              if((1225-i*2-j*2-2)+i*(i+1)+j*(j+1)==2015)
              System.out.println(i);
          }
     }
答案是:10  16

4.核桃的数量

    小张是软件项目经理,他带领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

题目分析:
1.无限列举可能的数目进行匹配,一旦匹配,停止运行
...  for (int i = 1; ; i++) {
          boolean flag=true;
          for (int j = 0; j < arr.length; j++) {
              if(i%arr[j]!=0){
                   flag=false;
                   break;
              }
          }
          if(flag){
              System.out.println(i);
              return;
          }
     }...

5.打印十字图
小明为某机构设计了一个十字型的徽标(并非红十字会啊),如下所示:


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

输入格式
一个正整数 n (n<30) 表示要求打印图形的层数。
输出格式
对应包围层数的该标志。
样例输入1
1
样例输出1

样例输入2
3
样例输出2

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

题目分析:
1.初始化图像
2.确立一个点,通过哪个点绕一圈
3.确立下一个点

...  int x=mid-2;
     int y=mid-2;
     int index=1;
     for (int i = 0; i < num; i++) {
          arr[x][y]='$';
          for (int j = 0; j < 2; j++) {
              y--;
              arr[x][y]='$';
          }...

...       for (int j = 0; j < index*4; j++) {
              y--;
              arr[x][y]='$';
          }
          for (int j = 0; j < 2; j++) {
              x++;
              arr[x][y]='$';
          }
          index++;
          x=x-2;
          y=y-2;  ...

要点注意:
1.画线的方式采用定义x,y。对x,y改变位置所得
2.因为长度涉及到圈数,为了方便运算,定义一个独立的index随圈数的遍历进行变化(不能直接用num ),记得用index来表示当前圈数
(耗时:16min15s)
6.打印大X
小明希望用星号拼凑,打印出一个大X,他要求能够控制笔画的宽度和整个字的高度。
为了便于比对空格,所有的空白位置都以句点符来代替。
要求输入两个整数m n,表示笔的宽度,X的高度。用空格分开(0<m<n, 3<n<1000, 保证n是奇数)
要求输出一个大X

例如,用户输入:
3 9
程序应该输出:
***.....***
.***...***.
..***.***..
...*****...
....***....
...*****...
..***.***..
.***...***.
***.....***

再例如,用户输入:
4 21
程序应该输出
****................****
.****..............****.
..****............****..
...****..........****...
....****........****....
.....****......****.....
......****....****......
.......****..****.......
........********........
.........******.........
..........****..........
.........******.........
........********........
.......****..****.......
......****....****......
.....****......****.....
....****........****....
...****..........****...
..****............****..
.****..............****.
****................****

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

题目分析:
1.先初始化图形背景
2.确定一个起始点,利用高的变化打印\
3.同上打印/,注意起始点-1:由高度确定的起点位置
...  for (int i = 0; i < arr.length; i++) {
          for (int j = 0; j < kuan; j++) {
              arr[i][j+i]='*';
          }
          for (int j = 0; j < kuan; j++) {
              arr[i][width-kuan-i+j]='*';
          }

     }...

7.移动距离
X星球居民小区的楼房全是一样的,并且按矩阵样式排列。其楼房的编号为1,2,3...
当排满一行时,从下一行相邻的楼往反方向排号。
比如:当小区排号宽度为6时,开始情形如下:

1  2  3  4  5  6
12 11 10 9  8  7
13 14 15 .....

我们的问题是:已知了两个楼号m和n,需要求出它们之间的最短移动距离(不能斜线方向移动)
输入为3个整数w m n,空格分开,都在1到10000范围内
要求输出一个整数,表示m n 两楼间最短移动距离。

例如:
用户输入:
6 8 2
则,程序应该输出:
4

再例如:
用户输入:
4 7 20
则,程序应该输出:
5

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

题目分析:
1.首先确定坐标的位置,然后进行相减获取它的绝对值
2.但是位置要怎么获取呢,行用/,列用%
3.不过有个问题就是奇偶的列位置不同,所以在获取之后需要判断修改
4.用%获取会把最后一列的数弄没,所以需要判断是否是整除,是的话写最后一列
5.用/获取会将刚刚满的数判断成1.多(多了一行),所以也需要判断是否整除,是的话不加行

...  int ox=one/length;
     int oy=one%length;
     int tx=two/length;
     int ty=two%length;

     if(one%length==0){
          oy=oy+length;
     }else{
          ox=ox+1;
     }
     if(two%length==0){
          ty=ty+length;
     }else{
          tx=tx+1;
     }
     if(ox%2==0){
          oy=length-oy+1;
     }
     if(tx%2==0){
          ty=length-ty+1;
     }
     System.out.println(Math.abs(ox-tx)+Math.abs(oy-ty));
注意事项:最后一个临界值对/&%都有影响,所以需要判断处理
8.冰雹数

任意给定一个正整数N,
如果是偶数,执行: N / 2
如果是奇数,执行: N * 3 + 1

生成的新的数字再执行同样的动作,循环往复。

通过观察发现,这个数字会一会儿上升到很高,
一会儿又降落下来。
就这样起起落落的,但最终必会落到“1”
这有点像小冰雹粒子在冰雹云中翻滚增长的样子。

比如N=9
9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
可以看到,N=9的时候,这个“小冰雹”最高冲到了52这个高度。

输入格式:
一个正整数N(N<1000000)
输出格式:
一个正整数,表示不大于N的数字,经过冰雹数变换过程中,最高冲到了多少。

例如,输入:
10
程序应该输出:
52

再例如,输入:
100
程序应该输出:
9232

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

题目分析:
1.这里有一个注意的就是输入的N不是一个数,而是小于N的所有数
2.循环所有小于N的数,当他们不为1的时候把结果全部收集到ArrayList中
3.遍历al,寻找里面的最大值
... for (int i = 1; i <= num; i++) {
          int temp=i;    //注意存入的是i
          al.add(temp);
          while(temp!=1){    //会变得值是temp
              if(temp%2==0){
                   temp=temp/2;
              }else{
                   temp=temp*3+1;
              }
              al.add(temp);
          }
     }...
注意要点:用来循环的数不要进行自身修改,很容易扰乱循环(所以要用到temp)

9.手机尾号
    30年的改革开放,给中国带来了翻天覆地的变化。2011全年中国手机产量约为11.72亿部。手机已经成为百姓的基本日用品!
    给手机选个好听又好记的号码可能是许多人的心愿。但号源有限,只能辅以有偿选号的方法了。
    这个程序的目的就是:根据给定的手机尾号(4位),按照一定的规则来打分。其规则如下:
    1. 如果出现连号,不管升序还是降序,都加5分。例如:5678,4321都满足加分标准。
    2. 前三个数字相同,或后三个数字相同,都加3分。例如:4888,6665,7777都满足加分的标准。注意:7777因为满足这条标准两次,所以这条规则给它加了6分。
    3. 符合AABB或者ABAB模式的加1分。例如:2255,3939,7777都符合这个模式,所以都被加分。注意:7777因为满足这条标准两次,所以这条标准给它加了2分。
    4. 含有:6,8,9中任何一个数字,每出现一次加1分。例如4326,6875,9918都符合加分标准。其中,6875被加2分;9918被加3分。
    尾号最终得分就是每条标准的加分总和!
    要求程序从标准输入接收数据,在标准输出上输出结果。
    输入格式为:第一行是一个整数n(<100),表示下边有多少输入行,接下来是n行4位一组的数据,就是等待计算加分的手机尾号。
    输出格式为:n行整数。

    例如,输入:
14
3045
0211
2345
6543
7777
8888
7878
7788
6688
2424
2244
9918
6789
8866
    则输出:
0
0
5
6
8
12
3
3
5
1
1
3
8
5

题目分析:
1.怎么处理多数据问题呢?获取数量,新建数组。通过遍历数组每一项调用方法。
2.怎么处理每一项之间的关系呢?将字符串转化为数组,因为操作的是整形类型,所以用Ascll的方式转化为整形(-'0')
3.拿到每一项的整形数据之后,根据其加分规则if进行加分,返回总分数

     int count=0;
     char[] c=arr.toCharArray();
     int[] nums=new int[4];
     for (int i = 0; i < nums.length; i++) {
          nums[i]=c[i]-'0';
     }
     if((nums[0]+1==nums[1]&&nums[1]+1==nums[2]&&nums[2]+1==nums[3])||(nums[0]-1==nums[1]&&nums[1]-1==nums[2]&&nums[2]-1==nums[3])){
          count+=5;
     }...
注意要点:处理
完成时间:16min
10.四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

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

题目分析:
1.这里使用暴力破解法,设置一个for循环,循环到5000000的开方(可知最小范围)
2.解决从小到大列出:每层循环都从上一个数开始
3.降低时间复杂度:循环出其他三个数之后,因为已知答案,第四个数可以用开方来获取
4.解决要求的是最大的数的问题,因为是从0开始循环的,所以第一个数就是最大的数,直接输出即可。
...  double maxNum= Math.sqrt(5000000);
     for (int i = 0; i <maxNum; i++) {
          for (int j = i; j < maxNum; j++) {
              for (int k = j; k < maxNum; k++) {
                   int l=(int)Math.sqrt(num-i*i-j*j-k*k);
                   if(i*i+j*j+k*k+l*l==num){
                        System.out.println(i+" "+j+" "+k+" "+l);
                        return;
                   }
              }
          }
     }
注意要点:for嵌套自身带从小到大排列特性

时间计算方法:
        long t1=System.currentTimeMillis();
...
  long t2=System.currentTimeMillis();
  System.out.println(t2-t1);
完成时间:8min
11.带分数
    100 可以表示为带分数的形式:100 = 3 + 69258 / 714
    还可以表示为:100 = 82 + 3546 / 197
    注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
    类似这样的带分数,100 有 11 种表示法。
题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!

例如:
用户输入:
100
程序输出:
11

再例如:
用户输入:
105
程序输出:
6

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

题目分析:
1.循环a与c,根据公式算出b的值     c为什么循环到10000,因为用最大的数除以10000最多也只有100
2.获取到abc之后要判断其出现且仅出现一次(不包括0,所以统计的时候要减去0)
3.判断的时候要判断,每个数出现的总和是9并且有出现的数的总和也是9
     for (int a = 1; a < num; a++) {
          for (int b = 1; b < 1000000/num; b++) {
              int c=(num-a)*b;
              String all=""+a+b+c;
              int[] arr=new int[10];
              int rel=0;
              for (int i = 0; i < all.length(); i++) {
                   arr[all.charAt(i)-'0']=1;
                   rel++;
              }
              int temp=0;
              for (int i = 1; i < arr.length; i++) {
                   temp+=arr[i];
              }
              if(rel==9&&temp==9){
                   count++;
              }

          }
     }
注意要点:
1.需要减少暴力的范围:第一个数循环到num即可,第二个数循环到1000000/num(公式得来最大可能),因为数字的要求是刚好9个,所以当判断不是9个的时候可以直接进行下一个循环。
2.最后一个数利用公式求得
(7min完成)
12.买不到的数目
    小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖。
    小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
    你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是17。大于17的任何数字都可以用4和7组合出来。
    本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入:
两个正整数,表示每种包装中糖的颗数(都不多于1000)

要求输出:
一个正整数,表示最大不能买到的糖数
不需要考虑无解的情况
例如:
用户输入:
4 7
程序应该输出:
17

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

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

题目分析:
1.循环足够多的可能结果存进数组里面,这里为了缩小循环的时间,用N/a来表示a最多的数量i,用公式(N-a*i)/b来表示b最多的数量j
2.因为计算的不是不同字符的个数,而是字符连续的长度。所以使用定义count的方式,当count的值为其中一个数的时候说明可以构成循环,最大的数就是当前的这个数减去a所得的值。如果没法做到连续就将计数器count清0.

     for (int i = 0; i < N/a; i++) {
          for (int j = 0; j < (N-a*i)/b; j++) {
              point[i*a+j*b]=1;
          }
     }
     int count=0;
     for (int i = 0; i < point.length; i++) {
          if(point[i]==1){
              count++;
              if(count==a){
                   System.out.println(i-a);
                   return;
              }
          }else{
              count=0;
          }
     }

注意事项:0的可能也要算上


0 0