一、枚举
🍊1.前言
距离蓝桥杯省赛的日子越来越近了😨😨😨,不知道大家准备的怎么样?🤔🤔🤔不管如何,到现在这个时候都不能慌。硬实力是一方面,但是也不能只顾着埋头刷题,蓝桥杯还是有很多技巧的。
首先我们应该清楚,蓝桥杯十道题,前面五道都是填空题,填空题只需要填上答案就可以。
换句话说我们不管使用什么算法,哪怕是手算只要算出答案也行,当然手算是没有办法的办法😜😜😜
那么有没有什么好的技巧呢?
我的答案是 暴力枚举,相信大家对暴力枚举都不陌生,也经常能在各大oj平台上看到诸如这个题暴力能不能解之类的讨论,许多题其实都可以暴力枚举,只是大部分题目都可能会超时,但是超时是超出了oj平台对改题目设置的限定时间,蓝桥杯的填空题可没有超时这个说法,只需要填写答案,而且许多编程
题暴力枚举也能拿不少分,那么我们为什么不选择更容易想到的暴力枚举呢?
大家都知道枚举简单,不就是把所有情况都列举出来吗,但是在实际写的时候,很多人并没有使用或者第一时间选择枚举,难道是害怕超时吗?经过了解几个小伙伴的想法后才知道原来大家不是不想用枚举,也不是不了解枚举,而是不知道该如何进行有效的枚举。
🍊2.枚举模板
我个人对可以枚举题目的理解结合oj平台上一些大佬的经验,总结出一个基本思想和一个大白话的模板
一个基本思想: 怎么简单怎么来,能for就for,不能for就while
一个白话模板:
1.找到要进行枚举的东西
2.要枚举东西的特性
3.枚举的上下边界
4.符合条件的判断
5.能否在枚举的基础上简单优化(视情况判断是否省略)
我们根据一个基本思想和一个白话模板结合往年蓝桥杯真题实践实践
二、例题分析
🌰1.四平方和
题目链接 (lanqiao.cn)
🍋1.题目描述
🍋2.题目分析
给定一个正整数,找四个数这四个数的平方相加 = 给定的正整数,且四个数从小到大排序。
1. 根据一个基本思想,能for就for,那我们就for,不是找四个数吗,那我就for四次
2. 要枚举的数有什么特性?都是正整数 大于0,而且我们也可以很容易等到最大不超
过这个正整数的平方根,这样我们同时也把枚举的上下边界解决了。
3. 符合条件的判断 就是四个数的平方相加看是否 等于 给定的数
根据以上思路我们很容易写出以下代码
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int num = (int) Math.sqrt(n);
for(int i = 0;i < num;i++ ) {
for(int j = 0; j < num; j++) {
for(int k = 0; k < num;k++) {
for(int l = 0; l < num;l++) {
if(i*i + j*j + k*k + l*l == n) {
System.out.println(i+" "+j+" "+k+" "+l);
return;
}
}
}
}
}
scanner.close();
}
}
这样就可以了吗?我们测试下发现只能得50分,为什么不能拿满分,不是说枚举可行吗?
大家先别着急,这个题是一道编程题,哈哈是不是很震惊,(注:蓝桥杯编程题测试数据
是分多个层次的,层次越高数据规模越大,分数越高)编程题竟然用枚举拿了一半的分。
但是我还是想拿满分,毕竟这个题看起来不难,这个时候就要考虑第五步了,能否进
行简单优化。
我们在小学都知道a+b = c,a、b、c三个数知道其中任意两个可以求第三个数,那么我们
代入本题,总共有五个数我们只要知道四个数就可求第五个数了,我们知道和(给定的
数),那么我们只需要枚举三个数,最后一个数就是和 减去 三个数的平方之和,我们
求出了第四个数的平方,这个时候还没有结束
因为我们只知道第四个数的平方,这个数的平方根是否符合题目条件是个正整数呢,
所以我们需要再判断一下是否是正整数,使用平方根相乘是否等于原来的数即可
🍋3.代码实现
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int num = (int) Math.sqrt(n);
for(int i = 0;i < num;i++ ) {
for(int j = 0; j < num; j++) {
for(int k = 0; k < num;k++) {
int temp = n - i*i -j*j-k*k;
if(temp == ((int)Math.sqrt(temp)*(int)Math.sqrt(temp))) {
System.out.println(i+" "+j+" "+k+" "+(int)Math.sqrt(temp));
return;
}
}
}
}
scanner.close();
}
}
这样我们就可以轻松拿满分了!!! 😀😀😀
🌰2.纯质数
题目链接 (lanqiao.cn)
🍋1.题目描述
🍋2.题目分析
首先看到这是一个填空题, 二话不说直接上来就枚举,枚举正整数
1. 能for就for
2. 正整数必须是纯质数,也就是这个数每个十进制数位都是质数,本身也是质数
3. 枚举上下边界题目给了1到20210605,使用个变量记录个数,每次符合条件就+1
4. 由于是个填空题,暂时不想优化
🍋3.代码实现
public class Main {
public static void main(String[] args) {
int res = 0;
for(int i = 2; i <= 20210605;i++) {
if(isprime(i) && f(i)) res++;
}
System.out.println(res);
}
static boolean isprime(int n) {
int num = (int) Math.sqrt(n);
for(int i = 2; i<= num; i++) {
if(n % i==0) return false;
}
return true;
}
static boolean f(int n) {
while(n != 0) {
int t = n%10;
if(t == 0 || t == 1 || t == 4 || t == 6 || t == 8 || t == 9) return false;
n /= 10;
}
return true;
}
}
注意代码在蓝桥云科的练习系统中运行超时,但是在本地是没问题的。我们直接在本地
运行出结果,填上(直接输出)就可以
🌰3.回文日期
题目链接 (lanqiao.cn)
🍋1.题目描述
🍋2.题目分析
首先是道编程题,可能会优化, 但是我还是枚举
题目说给一个八位正整数,表示日期,枚举的东西就是日期
1. 日期有什么特性? 月份不能超过12,每个月份的天数都是确定的,还要注意闰年的
情况
2. 枚举的上下边界 给定日期的下一天到89991231,(在蓝桥云课上的测试系统测试
数据到99999999,可能之后增加了数据规模。在实际比赛时,不会出现题目给定范围和
测试不符的情况,大家放心)
3. 符合条件的情况,一种是回文的,一种既是回文,又要满足ABABBABA
直接上代码,细节注释在代码中
🍋3.代码实现
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
boolean flag = true;
for(int i = n+1;i <= 99999999;i++) {
if(!valid(i)) continue;
if(f(i)) {
if(flag){
System.out.println(i);
flag = false;
}
if(check(i)) {
System.out.println(i);
break;
}
}
}
scan.close();
}
static boolean valid(int i) {
int[] month = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int yyyy = i/10000;
int mm = i / 100 % 100;
if(mm > 12 || mm == 0) return false;
if((yyyy % 4 == 0 && yyyy % 100 !=0) || yyyy % 400 == 0) month[2] = 29;
else month[2]=28;
int dd = i % 100;
if(dd > month[mm] || dd == 0) return false;
return true;
}
static boolean check(int i) {
int[] nums = new int[8];
int k = 0;
while(true) {
nums[k++] = i % 10;
i/=10;
if(i == 0) break;
}
if(nums[0] == nums[2] && nums[1] == nums[3] && nums[0] != nums[1]) return true;
else return false;
}
static boolean f(int i) {
String string = i +"";
StringBuffer sBuffer = new StringBuffer(string);
sBuffer.reverse();
return string.equals(sBuffer.toString());
}
}
成功通过!!!
由此可见,暴力枚举在蓝桥杯中占比较大,而且能够轻松得分,小伙伴们学废了吗🤣🤣🤣
如果文章对你有所帮助,希望能够三连支持一下🥰🥰🥰
|