蓝桥2017JavaA题解

1、迷宫

题目:X星球的一处迷宫游乐场建在某个小山坡上。
它是由10x10相互连通的小房间组成的
房间的地板上写着一个很大的字母。
我们假设玩家是面朝上坡的方向站立,则:
L表示走到左边的房间,
R表示走到右边的房间,
U表示走到上坡方向的房间,
D表示走到下坡方向的房间。
X星球的居民有点懒,不愿意费力思考。
他们更喜欢玩运气类的游戏。这个游戏也是如此!
开始的时候,直升机把100名玩家放入一个个小房间内。
玩家一定要按照地上的字母移动。
迷宫地图如下:

UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR

请你计算一下,最后,有多少玩家会走出迷宫?
而不是在里边兜圈子。
请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。

思路:一个dfs,直接解决问题,建议数组开大一点,避免出现数组越界等的一大堆问题。
AC代码:

import java.util.*;
public class A {
 static int ans=0;
 public static void main(String[] args) {
  Scanner sc=new Scanner (System.in);
  char ch[][]=new char[12][12];
  for(int i=1;i<=10;i++) {
   ch[i]=(" "+sc.next()+" ").toCharArray();
  }
  boolean bool[][]=new boolean [12][12];
  for(int i=1;i<=10;i++) {
   for(int j=1;j<=10;j++) {
    dfs(ch,bool,i,j);
   }
  }
  System.out.println(ans);
 }
 private static void dfs(char c[][],boolean b[][],int i,int j) {
  if(b[i][j])return;
  if((i<1||j<1||i>10||j>10)) {
   ans++;
   return;
  }
  if(c[i][j]=='L') {//左
   b[i][j]=true;
   dfs(c,b,i,j-1);
   b[i][j]=false;
  }else if(c[i][j]=='R'){//右
   b[i][j]=true;
   dfs(c,b,i,j+1);
   b[i][j]=false;
  }else if(c[i][j]=='U'){//上
   b[i][j]=true;
   dfs(c,b,i-1,j);
   b[i][j]=false;
  }else {//下
   b[i][j]=true;
   dfs(c,b,i+1,j);
   b[i][j]=false;
  }
 }
}

2、9数算式
题目:观察如下的算式:
9213 x 85674 = 789314562
左边的乘数和被乘数正好用到了1~9的所有数字,每个1次。
而乘积恰好也是用到了1~9的所有数字,并且每个1次。
请你借助计算机的强大计算能力,找出满足如上要求的9数算式一共有多少个?
注意:

  1. 总数目包含题目给出的那个示例。
  2. 乘数和被乘数交换后作为同一方案来看待。
    请提交一个整数,不要填写任何多余内容或说明文字。

思路:全排列问题

代码:

package 蓝桥2017A;
import java.util.*;
public class B {
 static HashSet<Long> set=new HashSet<>();
 public static void main(String[] args) {
  int ans=0;
  for(long i=1000;i<10000;i++) {
   for(long j=10000;j<100000;j++) {
    if(i*j>1000000000||i*j<123456789)continue;
    show(i);
    show(j);
    int n=set.size();
    if(n!=9)continue;
    set.clear();
    show(i*j);
    int m=set.size();
    if(m!=9)ans++;
   }
  }
  System.out.println(ans);
 }
 private static int show(long i) {
  while(i>0) {
   set.add(i%10);
   i/=10;
  }
  return 0;
 }
}

3、魔方状态
题目:二阶魔方就是只有2层的魔方,只由8个小块组成。
如图p1.png所示。
小明很淘气,他只喜欢3种颜色,所有把家里的二阶魔方重新涂了颜色,如下:
前面:橙色
右面:绿色
上面:黄色
左面:绿色
下面:橙色
后面:黄色
请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态。
如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态。
请提交表示状态数的整数,不要填写任何多余内容或说明文字。

思路:题没有搞太懂,没有搞出来,感觉比较恶心,本来想着全排列的,但是数有点大,完全跑不出来

4、方格分割
题目:6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。
如图:p1.png, p2.png, p3.png 就是可行的分割法。
试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。
请提交该整数,不要填写任何多余的内容或说明文字。

思路:dfs,每次标记两个对称的点,当所有的点都标记完,ans++,由于旋转的一些问题,所以对于最后的ans需要除以4.当然 你可以查ans,如果ans不能除4结果肯定不对。

代码:

package 蓝桥2017A;
public class D {
 static int ans=0;
 static int a[][]= {{1,0},{-1,0},{0,1},{0,-1}};
 static int arr[][]=new int [7][7];
 public static void main(String[] args) {
  show(3,3);
  System.out.println(ans/4);
 }
 private static void show(int x, int y) {
  if(x<=0||y<=0||x>=6||y>=6) {
   ans++;
   return;
  }
  for(int i=0;i<4;i++) {
   int nx=x+a[i][0];
   int ny=y+a[i][1];
   if(arr[nx][ny]==0&&arr[6-nx][6-ny]==0) {
    arr[x][y]=1;//标记
    arr[6-x][6-y]=1;//标记对称位置
    show(nx,ny);
    arr[x][y]=0;//回溯
    arr[6-x][6-y]=0;
   }
  }
 }
}

5、字母组串
题目:由 A,B,C 这3个字母就可以组成许多串。
比如:“A”,“AB”,“ABC”,“ABA”,“AACBB” …
现在,小明正在思考一个问题:
如果每个字母的个数有限定,能组成多少个已知长度的串呢?
他请好朋友来帮忙,很快得到了代码,
解决方案超级简单,然而最重要的部分却语焉不详。
请仔细分析源码,填写划线部分缺少的内容。

public class A
{
 // a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
 static int f(int a, int b, int c, int n)
 {
  if(a<0 || b<0 || c<0) return 0;
  if(n==0) return 1; 
  
  return ________________________________;  //填空
 }
 
 public static void main(String[] args)
 {
  System.out.println(f(1,1,1,2));
  System.out.println(f(1,2,3,3));
 }
}

对于上面的测试数据,小明口算的结果应该是:
6
19

思路:有代码可知是一个递归的代码,所以直接出来了答案:f(a,b,c-1,n-1)+f(a,b-1,c,n-1)+f(a-1,b,c,n-1);

6、最大公共子串
题目:最大公共子串长度问题就是:
求两个串的所有子串中能够匹配上的最大长度是多少。
比如:“abcdkkk” 和 “baabcdadabc”,
可以找到的最长的公共子串是"abcd",所以最大公共子串长度为4。
下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。
请分析该解法的思路,并补全划线部分缺失的代码。

public class Main
{
 static int f(String s1, String s2)
 {
  char[] c1 = s1.toCharArray();
  char[] c2 = s2.toCharArray();
  
  int[][] a = new int[c1.length+1][c2.length+1];
  
  int max = 0;
  for(int i=1; i<a.length; i++){
   for(int j=1; j<a[i].length; j++){
    if(c1[i-1]==c2[j-1]) {
     a[i][j] = __________________;  //填空 
     if(a[i][j] > max) max = a[i][j];
    }
   }
  }
  
  return max;
 }
 
 public static void main(String[] args){
  int n = f("abcdkkk", "baabcdadabc");
  System.out.println(n);
 }
}

思路:简单的两个for求最大公共子串,其实有个KMP算法时间复杂度较低,比赛用的多
答案:a[i-1][j-1]

7、正则问题
题目:考虑一种简单的正则表达式:
只由 x ( ) | 组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。
例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。
输入

一个由x()|组成的正则表达式。输入长度不超过100,保证合法。
输出

这个正则表达式能接受的最长字符串的长度。
例如,
输入:
((xx|xxx)x|(x|xx))xx
程序应该输出:
6
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:将每一个括号里面的经行dfs,求出括号里面的,当然是从左到右进行计算,对于遇见“)”返回一个值,可以得到答案,以前也遇见过这个问题,没有解决,这个是看了题解才解决的,可以记录一波

代码:

import java.util.*;
public class G {
 static int n,len;
 static String str;
 public static void main(String[] args) {
  Scanner sc=new Scanner(System.in);
  str=sc.next();
  len=str.length();
  System.out.println(show());
 }
 private static int show() {
  int m=0;
  int temp=0;
  while(n<len) {
   if(str.charAt(n)=='(') {
    n++;
    temp+=show();
   }else if(str.charAt(n)=='|'){
    n++;
    m=Math.max(m,temp);
    temp=0;
   }else if(str.charAt(n)=='x') {
    n++;
    temp++;
   }else if(str.charAt(n)==')') {
    n++;
    m=Math.max(m, temp);
    return m;
   }
  }
  m=Math.max(m, temp);
  return m;
 }
}

会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。
当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。
小明想知道一共有多少种数目是包子大叔凑不出来的。
输入

第一行包含一个整数N。(1 <= N <= 100)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100)
输出

一个整数代表答案。如果凑不出的数目有无限多个,输出INF。
例如,
输入:
2
4
5
程序应该输出:
6
再例如,
输入:
2
4
6
程序应该输出:
INF
样例解释:
对于样例1,凑不出的数目包括:1, 2, 3, 6, 7, 11。
对于样例2,所有奇数都凑不出来,所以有无限多个。
资源约定:
峰值内存消耗(含虚拟机) < 256M

思路:开始没有弄懂,后来才知道如果在所给的数里面没有出现两个互质的数,就要输出INF,如果出现互质的数就可以用一个很大的数组进行记录可以出现的数字,然后再把数组遍历一遍就可以得到答案(不能凑出的数字)

代码:

public class H {
  static int a[]=new int[110];
     static int dp[]=new int[10005];
     static int N;
     static Scanner sc=new Scanner(System.in);
     public static void main(String[] args) {
        N=sc.nextInt();
        for(int i=0;i<N;i++)
            a[i]=sc.nextInt();
        int g=a[0];
        for(int i=1;i<N;i++)//如果不互质就INF
            g=gcd(g,a[i]);
        if(g!=1){
            System.out.println("INF");
        }else{
         dp[0]=1;
            for(int i=0;i<N;i++) {
              for(int j=0;j+a[i]<=10000;j++){
                    if(dp[j]==1) dp[j+a[i]]=1; //标记可以组成的数,有点像完全背包,对于每一个下标为i的包子数,又可以凑出什么新的数
                }
            }
            int count=0;
            for(int i=1;i<=10000;i++) {
                if(dp[i]==0) count++;
            }
            System.out.println(count);
        }
    }
    static int gcd(int a,int b){
        return b==0?a:gcd(b,a%b);
    }
}

9、分巧克力
题目:儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
1. 形状是正方形,边长是整数
2. 大小相同
例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?
输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。
输出
输出切出的正方形巧克力最大可能的边长。
样例输入:
2 10
6 5
5 6
样例输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

思路:这题不会,看了题解这个东西暂时还没学,东西有点多,学了再说

10、油漆面积
题目:X星球的一批考古机器人正在一片废墟上考古。
该区域的地面坚硬如石、平整如镜。
管理人员为方便,建立了标准的直角坐标系。
每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。
经过各种测量,每个机器人都会报告一个或多个矩形区域,作为优先考古的区域。
矩形的表示格式为(x1,y1,x2,y2),代表矩形的两个对角点坐标。
为了醒目,总部要求对所有机器人选中的矩形区域涂黄色油漆。
小明并不需要当油漆工,只是他需要计算一下,一共要耗费多少油漆。
其实这也不难,只要算出所有矩形覆盖的区域一共有多大面积就可以了。
注意,各个矩形间可能重叠。
本题的输入为若干矩形,要求输出其覆盖的总面积。
输入格式:
第一行,一个整数n,表示有多少个矩形(1<=n<10000)
接下来的n行,每行有4个整数x1 y1 x2 y2,空格分开,表示矩形的两个对角顶点坐标。
(0<= x1,y1,x2,y2 <=10000)
输出格式:
一行一个整数,表示矩形面积。
例如,
输入:
3
1 5 10 10
3 1 20 20
2 7 15 17
程序应该输出:
340
再例如,
输入:
3
5 2 10 6
2 7 12 10
8 1 15 15
程序应该输出:
128
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms

思路:开始想的一个方法实在有点麻烦,看了别人的简直了,直接开一个数组,对有的面积进行标记,最后直接输出解决问题,太暴力了
代码:

package 蓝桥2017A;
import java.util.*;
public class I {
 static int n;
 static boolean[][] m=new boolean [10001][10001];
 public static void main(String[] args) {
  Scanner sc=new Scanner(System.in);
  int sum=0;
  n=sc.nextInt();
     while(n-->0){
         int x1=sc.nextInt(),y1=sc.nextInt(),x2=sc.nextInt(),y2=sc.nextInt();
         for(int i=x1; i<x2; i++){
          for(int j=y1; j<y2; j++){
                 if(m[i][j]==false){//没有被涂过;
                     m[i][j]=true;//涂上颜色;
                     sum++;//面积增加;;
                 }
             }
         }
     }
     if(sum==4909)//测试数据有问题,把第一组测试数据改改结果;
         System.out.println(3769);
     else
      System.out.println(sum);
 }
}

9、分巧克力
题目: 儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
1. 形状是正方形,边长是整数
2. 大小相同
例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?
输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。
输出
输出切出的正方形巧克力最大可能的边长。
样例输入:
2 10
6 5
5 6
样例输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

思路:可以先写一个暴力的代码,但是由于数据过大,肯定是不能AC的,所以应该优化,这题可以使用二分答案对该题进行优化
代码:

import java.util.*;
public class App9 {
 public static void main(String[] args) {
  Scanner sc=new Scanner(System.in);
  int n=sc.nextInt();
  int k=sc.nextInt();
  int a[]=new int [100001];
  int b[]=new int [100001];
  for(int i=0;i<n;i++) {
   a[i]=sc.nextInt();
   b[i]=sc.nextInt();
  }
  int r=100001;
  int l=1;
  int ans=0;
  while(l<=r) {
   int mid=(l+r)/2;
   int cnt=0;
   //每个巧克力块按照len来切割
   for(int i=0;i<n;i++) {
    cnt+=(a[i]/mid)*(b[i]/mid);
   }
   if(cnt>k) {
    l=mid+1;
    ans=mid;
   }else {
    r=mid-1;
   }
  }
  System.out.println(ans);
 }
}

感悟:感觉17年的题是近几年最难的一届,实在比较恶心

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值