前言

本人是二本院校大二的计算机系学生,已经报名了下一届的蓝桥杯省赛,整个寒假在家(这次的寒假挺久的哈哈)在b站学习了一些算法(现在会bfs走迷宫、dfs相关算法、递归回溯、常见排列算法),但是还是有很多算法都还不太熟悉,做起题来真是费劲。

这是我第二次完整的刷真题,第一次刷的是第七届的真题,其刷题笔记、思路和答案在:
https://blog.csdn.net/cxrshiz7890/article/details/104389137

不得不说,这次刷的第八届题目真是有点难度,开头几道题就难倒我了,花了好长时间想……(我想,考试时如果这样耗着就挂了,所以遇到不会的一定要跳过!)

不过,我相信通过思考总结后,一定会有所收获的!

刷题笔记

注:已完整解答的题目将会标记 (已完成) ,未完全解答出来的题目将在后续更新。代码设计题的代码不代表官方正确解法,只是通过了题目所给的测试而已,因此代码有误还请各位大佬指出哈哈。题目将保留原真题的完整描述,下次复习的时候可以强迫自己多读题(读懂题是关键啊!后面有道题读了十几分钟却不知道题目在讲什么,太浪费时间了!)

第一题、购物单(已完成)

【题目】:

小明刚刚找到工作,老板人很好,只是老板夫人很爱购物。老板忙的时候经常让小明帮忙到商场代为购物。小明很厌烦,但又不好推辞。这不,XX大促销又来了!老板夫人开出了长长的购物单,都是有打折优惠的。
小明也有个怪癖,不到万不得已,从不刷卡,直接现金搞定。现在小明很心烦,请你帮他计算一下,需要从取款机上取多少现金,才能搞定这次购物。取款机只能提供100元面额的纸币。小明想尽可能少取些现金,够用就行了。
你的任务是计算出,小明最少需要取多少现金。以下是让人头疼的购物单,为了保护隐私,物品名称被隐藏了。****     180.90       88折
****      10.25       65折
****      56.14        9折
****     104.65        9折
****     100.30       88折
****     297.15        半价
****      26.75       65折
****     130.62        半价
****     240.28       58折
****     270.62        8折
****     115.87       88折
****     247.34       95折
****      73.21        9折
****     101.00        半价
****      79.54        半价
****     278.44        7折
****     199.26        半价
****      12.97        9折
****     166.30       78折
****     125.50       58折
****      84.98        9折
****     113.35       68折
****     166.57        半价
****      42.56        9折
****      81.90       95折
****     131.78        8折
****     255.89       78折
****     109.17        9折
****     146.69       68折
****     139.33       65折
****     141.16       78折
****     154.74        8折
****      59.42        8折
****      85.44       68折
****     293.70       88折
****     261.79       65折
****      11.30       88折
****     268.27       58折
****     128.29       88折
****     251.03        8折
****     208.39       75折
****     128.88       75折
****      62.06        9折
****     225.87       75折
****      12.89       75折
****      34.28       75折
****      62.16       58折
****     129.12        半价
****     218.37        半价
****     289.69        8折需要说明的是,88折指的是按标价的88%计算,而8折是按80%计算,余者类推。
特别地,半价是按50%计算。请提交小明要从取款机上提取的金额,单位是元。
答案是一个整数,类似4300的样子,结尾必然是00,不要填写任何多余的内容。

【思路】:

很简单的数学题,逐个相乘然后求和即可。

但是……我还真的那么笨的一个个去算了,写了可能有15分钟吧,还好答案对了,不然到时候考试这么写,真的亏死了。

【正确答案】:

5200

巧妙做法:参考了网上大佬的做法,其实只需要把数据复制到一个空文本里,然后把*****用替换功能全部换成“+”号,把“半价”替换成 “ *0.5 ” (数字前面有个乘号),然后依次把xx折替换成相应的 “ *0.xx ”(前面有个乘号),最后把这段数据放到编译器里执行就好了。

第二题、纸牌三角形(已完成)

【题目】:

A,2,3,4,5,6,7,8,9 共9张纸牌排成一个正三角形(A按1计算)。要求每个边的和相等。
下图就是一种排法(如有对齐问题,参看p1.png)。A9 64   83 7 5 2这样的排法可能会有很多。如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?请你计算并提交该数字。注意:需要提交的是一个整数,不要提交任何多余内容。

【思路】:

把三角形展开来看成数组,然后用全排列把数组所有可能列举出来,然后判断有多少种情况符合即可。

这道题,我居然做了1个多小时,还做错了……我把它复杂化了,我分别写了3个方法来判断是否符合边长相等、是否是旋转的情况、是否是镜像的情况。这里记录一下错误的代码……下次复习的时候得长长记性……

package _8s_LanQiao;import java.util.ArrayList;
import java.util.List;public class A2
{static List<String> list = new ArrayList<String>();static int count = 0;//全排列public static void all(int[] a, int step){if(step == a.length - 1){if(checkE(a))  //如果符合边长和一样{StringBuffer sb = new StringBuffer();for(int i = 0; i < a.length; i++){sb.append(a[i]);}if(!checkR(a) && !checkM(a)) //如果这种情况不是镜像也不是旋转{list.add(sb.toString());count++;}}}for(int i = step; i < a.length; i++){int temp = a[i];a[i] = a[step];a[step] = temp;all(a, step + 1);temp = a[i];a[i] = a[step];a[step] = temp;}}//检查旋转public static boolean checkR(int[] a){int[] ex = new int[a.length*2];StringBuffer sb = new StringBuffer();for(int i = 0; i < a.length; i++)sb.append(a[i]);String now = sb.toString();for(int s = 0; s < list.size(); s++){StringBuffer sb2 = new StringBuffer(list.get(s) + list.get(s));String getstr = sb2.toString();if(getstr.indexOf(now) != -1) //匹配到了return true;  //这个是旋转的,不符合条件}return false;}//检查镜像public static boolean checkM(int[] a){StringBuffer sb = new StringBuffer();for(int i = 1; i < a.length; i++)sb.append(a[i]);String now = a[0] + sb.reverse().toString();for(int i = 0; i < list.size(); i++){String getstr = list.get(i);if(getstr.equals(now))   //匹配到了return true;  //说明是镜像,不符合条件}return false;}//检查是否边长和一样public static boolean checkE(int[] a){int sum = a[0] + a[1] + a[2] + a[3];int sum2 = a[3] + a[4] + a[5] + a[6];int sum3 = a[6] + a[7] + a[8] + a[0];if(sum == sum2 && sum2 == sum3)return true;   //边长一样,符合条件elsereturn false;}public static void main(String[] args){int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9,};all(a, 0);System.out.println(count); //得出错误答案 288}
}

除非思路很清晰,否则不要写那么长的代码!!!不要写那么长的代码!!不要写那么长的代码!!很容易出错。

【正确答案】:

144

其实全排列没有错,错的是判断情况的时候。其实只需算出边长相等的情况的次数count,然后再判断这其中包含的重复情况。

重复的情况1、旋转

这里我看错题意了!我以为旋转的意思是9个数字整体顺时针移动1位,真是糊涂啊[捂脸]。这个三角形有3个顶点,旋转的意思应该是从一个顶点到另一个顶点,也就是下面所示:

      A                                3                           29 6            旋转             7 4          旋转         8 54   8          ----->        5   9        ----->         6   73 7 5 2                         2 8 6 A                     A 9 4 3

也就是说,一个数组,就能衍生出其他2种重复的情况,所以总数要除以3,也就是 count / 3 就好了。

重复的情况2、镜像

一开始想的时候我又想复杂了,写了一通代码,结果不知道为何总是运行不了这个方法。

镜像,只有左右两种情况是重复的,count / 2即可。

所以总的来说,count / 3 / 2,就是正确答案了。

第三题、承压计算(已完成)

【题目】:

X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。7 5 8 7 8 8 9 2 7 2 8 1 4 9 1 8 1 8 8 4 1 7 9 6 1 4 5 4 5 6 5 5 6 9 5 6 5 5 4 7 9 3 5 5 1 7 5 7 9 7 4 7 3 3 1 4 6 4 5 5 8 8 3 2 4 3 1 1 3 3 1 6 6 5 5 4 4 2 9 9 9 2 1 9 1 9 2 9 5 7 9 4 3 3 7 7 9 3 6 1 3 8 8 3 7 3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。工作人员发现,其中读数最小的电子秤的示数为:2086458231请你推算出:读数最大的电子秤的示数为多少?注意:需要提交的是一个整数,不要填写任何多余的内容。

【思路】:

题目的意思就是把当前的数字分成两半,然后分别把一半的重量放在下一层的左右两个东西上,然后下一层的数字也这样重复操作。

从头部截取一部分数据来解释一下我的做法:

                            5 8 7 8 8 9 2 7 2

1、逐行扫描,把一行当成数组。比如扫到上面部分的第一行,记录当前行:

one = {5, 8}

2、然后另外定义一个“分散数组” arr,用来记录当前行分散(平分)后的值,那么会得到

//arr = {2.5, 2.5 + 4, 4}, 5/2 = 2.5, 8/2 = 4
arr = {2.5, 6.5, 4}

3、上面的分散数组即将堆叠到下一层上。继续记录下一行(7,8,8),把这一行的值加上上一行的分散数组的值(即 one[i] = arr[i] + one[i] )。

//one = {7 + 2.5, 8 + 6.5, 8 + 4}
one = {9.5, 14.5, 12}  //这一行的重量,既包括原本该行的重量,又包括上一行的重量

也就是说,下面的金字塔,左侧和右侧是等效的

                  5 8               7 8 8    ========  9.5  14.5  129 2 7 2            9    2    7     2

然后重复以上步骤累计叠加,最后一行获得的数组就是每个电子秤的值。然后在电子秤上寻找最小值,和题目给出的“2086458231”进行比对,肯定会有比例关系,然后在电子秤上寻找最大值乘以这个比例应该就是最终答案了。

值得注意的是,这样除下去会出现很多的小数(金字塔有29层,小数部分起码会超过小数点后20位),这样会影响我们的判断。于是可以把金字塔每个数字都乘以2^29次方,这样就能保证从头除到尾都不会出现小数了,到时候在从输出的结果中判断即可。

【正确答案】:

72665192664

代码如下:

package _8s_LanQiao;import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;public class A3
{public static void main(String[] args) throws Exception{// Text文件File file = new File("E:\\1.txt"); // 构造一个BufferedReader类来读取文件BufferedReader br = new BufferedReader(new FileReader(file)); String s = null;//上一个数组long[] last = new long[30];while ((s = br.readLine()) != null) // 使用readLine方法,一次读一行{               //拿到一个数组(把当前行变成数组)String[] one = s.split(" ");if(one.length == 1)        //金字塔顶的数组自己赋值,因为下面for循环赋值不了这个只有单个元素的数组last[0] = Integer.valueOf(one[0]) * (long)Math.pow(2, 29);else{long[] arr = new long[one.length + 1];   //用来记录"分散后的值"for(int i = 0; i < one.length - 1; i++){//分散当前数组long half = last[i] / 2;  //记录这个数字的一半的值arr[i] = arr[i] + half;      //这个一半的值会传给下一层左侧的数字arr[i + 1] = arr[i + 1] + half;  //这个一半的值会传给下一层右侧的数字}//开始叠加到下个数组for(int i = 0; i < one.length; i++){last[i] = arr[i] + Integer.valueOf(one[i]) * (long)Math.pow(2, 29);}}}br.close();//找到最大值, 这里的最大值就是题目要求出来的值。long max = last[0];for(int i = 0; i < last.length; i++){if(last[i] > max)max = last[i];}System.out.println(max);   //输出72665192664}
}

对于上面的代码,我是把金字塔数据放进一个空的txt文本里,然后用网上查的读取文件的方法逐行读取(就是这位大佬的方法),然后构造数组,再进行相应的计算即可。

"1.txt"文件的内容:

7
5 8
7 8 8
9 2 7 2
8 1 4 9 1
8 1 8 8 4 1
7 9 6 1 4 5 4
5 6 5 5 6 9 5 6
5 5 4 7 9 3 5 5 1
7 5 7 9 7 4 7 3 3 1
4 6 4 5 5 8 8 3 2 4 3
1 1 3 3 1 6 6 5 5 4 4 2
9 9 9 2 1 9 1 9 2 9 5 7 9
4 3 3 7 7 9 3 6 1 3 8 8 3 7
3 6 8 1 5 3 9 5 8 3 8 1 8 3 3
8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9
8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4
2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9
7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6
9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3
5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9
6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4
2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4
7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6
1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3
2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8
7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9
7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6
5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

运行后,最后一行数组(全部都是0的那一行)得到的结果是:

2928017717
9614247319
14239908242
18309604302
25052706191
31608660493
35591200180
39001205292
45898456845
52477249327
57251678638
62619220562
69215203679
72544032621
72665192664 //最大值
72404929768
68414729111
63620724941
58101345486
50610064018
46361902021
42903151375
39187912500
36994830636
32752069415
26160343661
19595172402
14435118862
8134346317
2086458231  //最小值

这个就是所谓的每个“电子秤”算出的结果,然后我们就观察每个电子秤上的数值,先找到最小值。最小值就是最后一个,即“2086458231”,这就巧了!这不就是题目提到的数值吗!所以我们只需要找到这其中的最大值,肯定就是电子秤的最大值(也就是正确答案)了。

第四题、魔方状态

注:这道题思路是使用bfs把每种情况列举,然后使用set集合去重,这其中代码很复杂(C语言实现都需要120+行代码),如果到了真正考试的时候,我觉得可以放弃这道题了。

【题目】:

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

第五题、取数位(已完成)

【题目】:

求1个整数的第k位数字有很多种方法。
以下的方法就是一种。public class Main
{static int len(int x){if(x<10) return 1;return len(x/10)+1;}// 取x的第k位数字static int f(int x, int k){if(len(x)-k==0) return x%10;return ______________________;  //填空}public static void main(String[] args){int x = 23513;//System.out.println(len(x));System.out.println(f(x,3));}
}对于题目中的测试数据,应该打印5。请仔细分析源码,并补充划线部分所缺少的代码。注意:只提交缺失的代码,不要填写任何已有内容或说明性的文字。

【思路】:

1、先观察len() 函数。

 static int len(int x){if(x<10) return 1;return len(x/10)+1;}

这个函数的作用和它的名字一样,意思是计算x是几位数。因为这是一个递归函数,返回值是len(x / 10) + 1,也就是说每返回一次,x就会少一位(从最低位开始少),同时会计数一次,当x少到不能再少了(x < 10),返回1,然后再逐个递归返回,就可以得到位数。

上面的话有点拗口,刚接触时我也不懂这个函数是什么意思(新手最头疼的就是递归回溯了),仔细了解了一下终于明白了,用下面方式表示可能更直观一点。

计算len(54321)
递归计算:-----------------------------------------------
len(54321) = len(5432) + 1len(5432) = len(543) + 1len(543) = len(54) + 1len(54) = len(5) + 1len(5) = 1
回归计算:-----------------------------------------------     len(54) = 1 + 1 = 2len(543) = 2 + 1 = 3len(5432) = 3 + 1 = 4
len(54321) = 4 + 1 = 5

2、明白了len()函数的用法后,再来看看f() 函数。

 static int f(int x, int k){if(len(x)-k==0) return x%10;return ______________________;  //填空}

这里不妨设一个比较极端的例子,x = 321, k = 3作为参数传入执行函数:

f(321,3)

传入参数后,进行if条件判断,可以发现条件成立,直接返回 x % 10 = 1;(从这里发现了,第k位上的数字,其实指的是从左到右数第k个数字)

好的,那么横线上应该填什么呢?我们试着把x = 4321, k = 3传入

f(4321,3)

首先进来,if条件肯定判断不通过,所以需要用到我们填空部分的代码。我们要得到的值是"2",即 f(4321,3) = 2 .那么怎样才能让if条件通过并返回2呢?

我们可以逆推,如果返回的是2,那么这个2一定是在个位,因为只有这样x %10才能等于2。

所以我们的关键在于,如何把4321变成432,很简单,4321 / 10 = 432. 也就是说,我们需要执行f(432, 3),那么就会返回2了。所以需要在 f(4321,3) 里面再执行 f(432,3) 所以填空部分是一个递归,也就是:

 static int f(int x, int k){if(len(x)-k==0) return x%10;return f(x/10, k);  //填空}

【正确答案】:

f(x/10, k);

第六题、最大公共子串(已完成)

【题目】:

最大公共子串长度问题就是:
求两个串的所有子串中能够匹配上的最大长度是多少。比如:"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);}
}

【思路】:

可以在草稿本上寻找规律,其实举个例子就很容易得出答案了。(下面写的有点复杂,建议拿纸和笔再写一下,挺容易找到规律的。)

代码中提供了两个字符串,把它们分别转化成了数组c1和c2,然后又开辟了一个二维数组a,行是c1.length + 1, 列是 c2.length + 1, 所以我们不妨画个图走一遍代码流程。

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

我们需要判断"abcdkkk"和"baabcdadabc"的最大公共子串,那么开辟的二维数组就是如下表格所示。其中:

1、横向是索引j, 纵向是索引i,自动初始化为0, 由于for循环索引从1开始,所以等于0的部分全部用"-"代替。

2、由于不知道划线部分应该填什么,就暂时把a[i][j]赋值为1作为标记,于是能得到以下表格:

0 1 b 2 a 3 a 4 b 5 c 6 d 7 a 8 d 9 a 10 b 11 c
0 - - - - - - - - - - - -
1 a - 0 1 1 0 0 0 1 0 1 0 0
2 b - 1 0 0 1 0 0 0 0 0 1 0
3 c - 0 0 0 0 1 0 0 0 0 0 1
4 d - 0 0 0 0 0 1 0 1 0 0 0
5 k - 0 0 0 0 0 0 0 0 0 0 0
6 k - 0 0 0 0 0 0 0 0 0 0 0
7 k - 0 0 0 0 0 0 0 0 0 0 0

通过表格可以得知,公共子串在表格中是以对角线形式存在的,而且很容易知道对角线长度其实就是公共子串的长度。因此,为了记录长度,当执行到
a[i][j]=__________时,这里的值应该是沿着对角线自增1,然后变量max会自动记录最大值。因此答案为:
a[i][j] = a[i-1][j-1] + 1;

【正确答案】:

a[i][j] = a[i-1][j-1] + 1;

第七题、日期问题(已完成)

【题目】:

小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在
1960年1月1日至2059年12月31日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,
有采用月/日/年的,还有采用日/月/年的。更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,
存在很多可能的日期与其对应。  比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。  给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?输入
----
一个日期,格式是"AA/BB/CC"。  (0 <= A, B, C <= 9)  输入
----
输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。多个日期按从早到晚排列。  样例输入
----
02/03/04  样例输出
----
2002-03-04
2004-02-03
2004-03-02  资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

【思路】:

现在回过头来看官网对历年真题的解答,发现之前写的代码存在很大的漏洞!很可能超过一半的数据都不能够通过测试。

错误在于yy_MM_dd(int y, int m, int d) 这个方法中。之前在这个方法中我只判断了(day > 31)的情况,殊不知其实还有很多情况需要判断,比如1、3、5、7、8月才有31天,而2月的情况又要分成闰年(29天)平年(28天)

因此,重新修改一下方法yy_MM_dd(int y, int m, int d) 后的具体思路如下:

1、写一个方法 yy_MM_dd(int y, int m, int d), 参数从左到右分别是指年、月、日。在方法中:
①利用参数y构造年份字符串year;
②利用参数m构造月份字符串month,如果不能构造(如m>12),提前return;
③利用参数d构造日的字符串day,如果不能构造(如d>31),提前return;
然后打印(year + month + day),即可出来结果。

1、写一个方法 yy_MM_dd(int y, int m, int d), 参数从左到右分别是指年、月、日。

①利用参数y构造年份字符串year;

②利用参数m构造月份的字符串month;如果不能构造(如m>12),提前return;

③利用参数d构造日的字符串day,并进行一系列的判断(如判断该月应该是30天还是31天、该年是闰年还是平年),如果发现不能构造,提前return;

2、输入的形式是 02/03/04,用 数组t 从左到右存储这3个数字。对于输入的日期(如02/03/04),分成以下三种情况(注意方法的参数从左到右是年、月、日):

①这个“日期”有可能是年/月/日的格式。把02当成年,把03当成月,把04当成日,执行一次方法yy_MM_dd(02,03,04),也就是yy_MM_dd(t[0],t[1],t[2]).

②这个“日期”也有可能是月/日/年的格式。把02当成月,把03当成日,把04当成年,执行一次方法yy_MM_dd(04,02,03),也就是yy_MM_dd(t[2],t[0],t[1]).

③这个“日期”也有可能是日/月/年的格式。把02当成日,把03当成月,把04当成年,执行一次方法yy_MM_dd(04,03,02),也就是yy_MM_dd(t[2],t[1],t[0]).

也就是说,在main里执行3次 yy_MM_dd() 方法,只不过3次执行方法时传入的参数顺序不同。

【参考答案】:

package _8s_LanQiao;import java.util.Scanner;public class A7
{//年--月--日的情况public static void yy_MM_dd(int y, int m, int d){String year, month, day;//**********年*********if(60 <= y && y <= 99)year = "19" + y;else if(0 <= y && y <=9)year = "200" + y;elseyear = "20" + y;//**********月*********if(1 <= m && m <= 9)month = "0" + m;else if(10 <= m && m <= 12)month = "" + m;elsereturn;//**********日*********int max = 30; //记录日的最大值可以是多少(如31、28(平年)、29(闰年)),先初始化为30int inty = Integer.valueOf(year);//逐月判断switch(m){//如果是二月的情况case 2://判断是否是闰年。记住口诀:四年一闰,百年不闰;四百年再闰。if( (inty % 4 == 0 && inty % 100 != 0 ) || inty % 400 == 0)max = 29;elsemax = 28;break;//每月有31天的情况case 1: case 3:case 5:case 7:case 8:case 10:case 12:max = 31;break;//其他情况就是每月有30天(已在上面初始化)}if(1 <= d && d <= 9)day = "0" + d;else if( 10 <= d && d <= max )day = "" + d;elsereturn;System.out.printf("%s-%s-%s\n", year, month, day);}public static void main(String[] args){Scanner sc = new Scanner(System.in);String time = sc.nextLine();String[] t = time.split("/");    //分割int aa = Integer.valueOf(t[0]);int bb = Integer.valueOf(t[1]);int cc = Integer.valueOf(t[2]);//参数顺序: 年-月-日yy_MM_dd(aa, bb, cc);  //可能是 年-月-日yy_MM_dd(cc, aa, bb);    //可能是 月-日-年yy_MM_dd(cc, bb, aa);    //可能是 日-月-年}}

第八题、包子凑数

注:该题代码虽通过了题目给出的测试,但是时间复杂度太高,到真正考试时有可能有些例子会运行超时,等到后面我知道了更优的解法后再回来补充。(考试时这样写应该也能得到一点分的)

建议看官网对该题的讲解!我感觉这道题我的思路不对,以下思路及代码不建议作为解题的参考,建议直接看官网源码(在我自己写的代码后面)。这道题考虑到了使用完全背包(dp)的算法(我还没学习到),具体思路建议到官网看题解。

【题目】:

小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有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,所有奇数都凑不出来,所以有无限多个。

【思路】:

题目简化过来的意思就是:给定几个数(a1,a2, … ,an),由这几个数随意组合凑正整数(这几个数都有无限个),求出不能凑出正整数的数量。
1、比如(3,4)两个数,1、2、5就凑不出来。
6可以凑出来,3+3;
7也可以,3+4;
8 = 4+4;
9 = 3+3+3;
10 = 3+3+4;
11 = 4+4+3;
12 = 4 + 4 + 4;
—分界线—
13 = 3+3+3+4;
14 = 3+3+4+4;
……
2、再举个例子,(4,5)两个数,1、2、3、6、7凑不出来。
8 = 4+4;
9 = 4+5;
10 = 5+5;
11凑不出来。
12 = 4+4+4;
13 = 4+4+5;
14 = 5+5+4;
15 = 5+5+5;
16 = 4+4+4+4;
17 = 4+4+4+5;
18 = 5+5+4+4;
19 = 5+5+5+4;
20 = 5+5+5+5;
—分界线—
21 = 4+4+4+4+5;
22 = 4+4+4+5+5;
……
通过这两个例子,大胆推测,如果两个数(a,b)组合起来,在区间 [a*b, +∞) 内任意整数都可以通过(a, b)凑出来。因此我们只需要考虑区间 (0, a*b] 内有多少个数不能被表示即可。
于是代码具体步骤如下:
1、比如(3,4)两个数,开辟一个长度为3×4的数组。能凑的数用1标记。
2、列一个方程,3x+4y=C,先固定C,然后再固定y,如果得出x有正整数解,说明这个C可以通过3和4凑出来。比如3x + 4 = 7,存在正整数解x = 1,因此7 可以通过3 + 4凑出来。
(以上步骤另写一个方法 comb(int a, int b) 实现)
3、由于输入的数字不一定只有两个,多个数的话,那就两两分组,依次执行以上方法(开辟的数组长度我大胆推测为两个最小的数之积,然后这个数组需要作为“全局变量”,即多组数据共享这个数组),如果参数a和b都是偶数,那么不执行这个方法。

【参考代码】:

以下是自己写的代码,当测试数据只有2个数字时,代码可通过,未测试多于2个数字时的正确性。建议参考官网源码 (在这段代码的后面);

package _8s_LanQiao;import java.util.Arrays;
import java.util.Scanner;public class A8
{// ax + by = C -->  x = (C - by)/apublic static void comb(int a, int b, int[] book){ int count = 0;for(int C = 1; C < book.length; C++){for(int y = 0; b*y <= C; y++){int x = (C - b * y) / a;//成立说明x是正整数,可以表示,同时标记bookif(a*x + b*y == C && book[C-1] != 1) {book[C-1] = 1;}}}}public static void main(String[] args){Scanner sc = new Scanner(System.in);int N = sc.nextInt();int[] n = new int[N];for(int i = 0; i < n.length; i++)n[i] = sc.nextInt();//初始化标记数组Arrays.sort(n);int[] book = new int[n[0] * n[1]];//两两组合执行方法。for(int p = 0; p < n.length - 1; p++){for(int q = p + 1; q < n.length; q++){if( !(n[p] % 2 == 0 && n[q] % 2 == 0) )comb(n[p],n[q], book);}}//算出(0, a*b]区间内有多少个数没被标记(即不能表示)int count = 0;for(int i = 0; i < book.length; i++){if(book[i] == 0)count++;}if(count == book.length)  //如果开辟的数组一个数都没有标记,那么就输出INFSystem.out.println("INF");elseSystem.out.println(count - 1);}}

【官方题解源码】

public class _08_包子凑数 {static int n, g;static int[] a = new int[101];static boolean[] f = new boolean[10000];static int gcd(int a, int b) {if (b == 0) return a;return gcd(b, a % b);}public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();f[0] = true;for (int i = 1; i <= n; ++i) {a[i] = sc.nextInt();if (i == 1) g = a[i];//初始化最大公约数else g = gcd(a[i], g);//完全背包的递推for (int j = 0; j < 10000 - a[i]; ++j) {if (f[j]) f[j + a[i]] = true;}}if (g != 1) {System.out.println("INF");return;}//统计个数int ans = 0;for (int i = 0; i < 10000; ++i) {if (!f[i]) {ans++;}}System.out.println(ans);}
}

第九题、分巧克力(已完成)

【题目】:

    儿童节那天有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

【思路】:

1、按照面积来分。把每块巧克力的面积加起来,然后除以人数,就能得到每个人理论上得到的巧克力的面积(记为sq)。

2、然后把该面积(sq)开根号,得到的数向下取整,作为每块巧克力的边长(记为bian,此时的bian一定是理论上最好的情况)

3、以这个bian为标准,来计算巧克力是否够分。

注意:计算巧克力是否够分时,如果巧克力的最短边小于bian,那么一定要把这个最短边赋值给bian,然后重新计算。

如果不够分,bian–;

4、直到bian减到全部巧克力够分了,输出bian;如果bian等于1,直接输出1;

举例:

1、现有一个6×6的巧克力,8个人分。其总面积为36,理论上每个人得到的巧克力面积为:sq = 36/8 = 4.5

2、sq开根号,得到理论上每个人得到的巧克力的最大边长bian = √4.5 ≈ 2.1213……然后向下取整,即bian = 2;

3、把这个大巧克力的长(为6)除以bian,得到3;把这个巧克力的宽(为6)除以bian,得到3;也就是说,这个巧克力能分出3 × 3 = 9 个bian 为2的巧克力。9 >= 8,够每个人分,直接输出bian = 2。

【参考答案】:

package _8s_LanQiao;import java.util.Scanner;public class A9
{public static void main(String[] args){//      System.out.println(Math.sqrt(4.5));Scanner sc = new Scanner(System.in);int N = sc.nextInt();  //巧克力个数int K = sc.nextInt();   //人数int[][] cho = new int[N][2];int sq = 0;   //统计面积for(int i = 0; i < cho.length; i++) //第i个巧克力{//0是宽,1是长cho[i][0] = sc.nextInt();cho[i][1] = sc.nextInt();sq += cho[i][0] * cho[i][1];}//返回平方根,强转为int只保留整数部分,相当于向下取整int bian = (int)Math.sqrt(sq);while(true){int count = 0;for(int i = 0; i < cho.length; i++){int m = cho[i][0] / bian;   //看宽能容纳多大的bianint n = cho[i][1] / bian;    //看长能容纳多大的bianint min = Math.min(cho[i][0], cho[i][1]);if(min < bian)   //保证bian小于等于每个巧克力的最短边。{bian = min;i = -1;count = 0;continue;}count += m * n;}if(count >= K || bian == 1)break;elsebian --;}System.out.println(bian);}}

第十题、k倍区间(已完成)

注:该题代码运用的是暴力法,可能有些测试会超时,如果等到后面知道了更优的解法,再回来补充。

【题目】:

给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。  你能求出数列中总共有多少个K倍区间吗?  输入
-----
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)  输出
-----
输出一个整数,代表K倍区间的数目。  例如,
输入:
5 2
1
2
3
4
5  程序应该输出:
6

【思路】:

想着这个是最后一题了,按照我刷题的速度,考试时写到这一题,时间也应该所剩无几了。所以花了不到10分钟写了一个暴力法。

就是把这个数组的所有公共子串列举出来,然后统计总和,如果总和是k的倍数,计数count++即可。

【参考答案】:

package _8s_LanQiao;import java.util.Scanner;public class A10
{public static void main(String[] args){Scanner sc = new Scanner(System.in);int N = sc.nextInt(); //有多少个元素int K = sc.nextInt();int[] arr = new int[N];for(int i = 0; i < arr.length; i++)arr[i] = sc.nextInt();int count = 0;for(int i = 0; i < arr.length; i++){int sum = 0;for(int j = i; j < arr.length; j++){sum += arr[j];if(sum % K == 0)    //成倍数count ++;}}System.out.println(count);}}

总结

刷题其实就是为了积累经验,能够在刷题的过程认识到自己缺失的知识点,那么刷题就是有效果的。以上所有代码仅供参考,不代表官方解法(官方源码除外)。其实代码也不是注重于结果,而是注重刷题时的思考过程,熟悉了各种题目的套路考试起来才能得心应手啊。

2017年第八届蓝桥杯JavaB组省赛 刷题笔记、思路及答案相关推荐

  1. 2018年第九届蓝桥杯 JavaB组省赛 刷题思路及答案

    前言 本人是二本院校大二的计算机系学生,已经报名了下一届的蓝桥杯省赛,整个寒假学习了很多算法知识,我是看<算法很美>这个课程学习算法的,一套学习下来确实受益匪浅,视频在b站上面都有. 此前 ...

  2. 第八届蓝桥杯JavaB组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.购物单 题目描述 小明刚刚找到工作,老板人很好,只是老板夫人很爱购物.老板忙的时候经常让小明帮忙到商场代为购物.小明很厌烦,但又不好推 ...

  3. 2017年第八届蓝桥杯 JavaB组国赛 第五题 填字母游戏

    标题:填字母游戏 小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说: "我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了". K大师在纸上画了一行n个格 ...

  4. 2018第九届蓝桥杯JavaB组省赛真题及详解

    2018第九届蓝桥杯JavaB组省赛真题及详解 第一题:第几天 第二题:方格计数 第三题:复数幂 第四题:测试次数 第五题:快速排序 第六题:递增三元组 第七题:螺旋折线 第八题:日志统计 第九题:全 ...

  5. 第十届蓝桥杯JavaB组省赛真题

    试题 A: 组队 本题总分:5 分 [问题描述] 作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分如下表所示. ...

  6. 第九届蓝桥杯JavaB组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.第几天 题目描述 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数 ...

  7. 2015蓝桥杯b组java_Java实现第十一届蓝桥杯JavaB组 省赛真题

    试题 A: 指数计算 本题总分:5 分 [问题描述] 7 月1日是建党日,从1921年到2020年, 已经带领中国人民 走过了 99 年. 请计算:7 ^ 2020 mod 1921,其中A mod ...

  8. 2019蓝桥杯Java决赛题答案_2019第十届蓝桥杯JavaB组省赛真题详解

    目录 题解待更新 第一题:组队 题目描述 做为篮球队教练,你须要从如下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分以下表所示.请你计算 ...

  9. 第六届蓝桥杯JavaB组省赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.三角形面积 题目描述 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何 ...

最新文章

  1. 设计模式 之美 -- 工厂方法模式
  2. A beginner’s guide to Cache synchronization strategies--转载
  3. PMcaff微课堂 | 洋葱淘elya妞,前百度UX Leader:独门创业经验,产品秘籍
  4. [转载]TopCoder兼职赚钱入门(Part. 1)
  5. Python数据结构和算法
  6. 一般筛法和快速线性筛法求素数 求素数的一点总结
  7. Objective-C消息转发
  8. 从零开始学keras之使用预训练的卷积神经网络
  9. el-jy-ii计算机组成原理实验报告,EL-JY-II型计算机组成原理实验系统
  10. jenkins vue 打包特别慢_Jenkins 自动化部署
  11. 基于Flash的开源网页播放器使用方法(FlowPlayer/AdobePlayer)
  12. php图片64位处理,php实现图片以base64显示的方法
  13. 推荐15款优秀的chrome插件,每一款都是神器
  14. 音调、响度 和 周期(频率) 占空比 的关系
  15. 腾讯云搭建vsftpd服务器
  16. 活码二维码免费平台有哪些呢?
  17. 王兴的190条程序员技术人生的思考!
  18. 关于以太坊公开的4个测试网络的区别:
  19. 从技术走向管理(李元芳履职记)--摘抄总结
  20. excel导出 服务器运行失败,用vc生成excel报表,提示“创建excel服务器失败”,该如何处理...

热门文章

  1. JS十进制转二进制(可控制位数)
  2. IIS配置 安全性配置
  3. mbedtls学习(9)数字签名RSA、DSA、ECDSA
  4. 【Kafka】Kafka消费者组三种分区分配策略roundrobin,range,StickyAssignor
  5. 微型计算机硬盘序列号,C# 读取硬盘信息 ManagementClass类
  6. Python图片抓取实操
  7. C语言:strdup函数的使用
  8. python开发鸡兔同笼
  9. 查询单个商品,分页展示商品
  10. BP神经网络能够做什么,bp神经网络构建步骤