蓝桥杯真题历年总结及常用赛题模板

一、比赛时一定要看清比赛题目

在我两年参与了四次的比赛中,绝大多数出错与测试输出不符都是因为大概看题后感觉题目简单或是有一点思路,就直接上手写代码。当代入测试数据的时候才发现错误,往往此类错误在审题的时候都可以避免。比赛中最重要的就是先仔细阅读题目找出可能会有的坑,再开始写代码,可以节省很多时间也可使代码不会经过多次修改bug看起来冗余。

二、把握比赛时间不要死磕

蓝桥杯比赛一共10题(直接填答案题5 + 编程题5题),分值分别为5,5,10,10,15,15,20,20,25,25。比赛时间一共为4小时。可见前面五道填答案题最高才15分,编程题最低都有15分。所以前面填空题如果难算并不需要纠结,直接跳过就好。一般能写两道填空题加一道半编程题都可以在省赛获得奖。

三、能暴力的题就不要想得很复杂

若是遇到比较难的题,如最后两题。一般最后两题都是有可以暴力破解的方法可以通过一部分数据的,如果觉得时间和能力不够,就直接暴力破解不需要仔细深究时间复杂度和空间复杂度问题。在比赛中就做到尽可能拿分就好,编程题并非测试数据通过就一定能得满分。可能会存在测试用例没有覆盖到的数据,或者测试超大数据,算法不够好的话复杂度太高也会出现部分数据不能通过。如果时间足够的话就可以考虑一下特殊数据或者大数据能否通过,进而优化自己算法。如果时间不够,直接暴力破解(如:多重嵌套循环)不需要考虑那么多。

四、高频出现的算法、比赛技巧及模板

参加蓝桥杯的同学一定要把历年真题自己去写一遍,可能初学算法的同学看比赛题会有些难度,但是如果能专研比赛试题的算法和进行总结,通过练习两三套真题想要获得一个省赛将一定不难。以下是我通过从15年到20年省赛与国赛题所得出的总结。

1.排序算法

  • 最常见,也是大一学生算法小白最浪费时间的去写的算法
  • 在比赛中尽量使用Java,C++自带的排序算法,此类算法平均效率比初学者所学的冒泡排序和选择排序算法高,也可以减少很多写代码的时间。
//在java中实现自带快速排序
int[] x = {9,6,3,8,5,2,7,4,1,0};
Arrays.sort(x); //只需把需要排序的数组放进去就行
//在c++中使用模板函数sort()
int x[10]= {9,6,3,8,5,2,7,4,1,0};
sort(x,x + 10);
  • 也可根据题意自行写出对于此题效率更高的算法,如:桶排序,归并排序等。对于蓝桥杯比赛自带的排序算法一般就住够用了。

2.全排列

  • 全排列几乎在每年的比赛中都有出现。
  • 全排列的定义为
    从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

公式:全排列数f(n)=n!(定义0!=1),如1,2,3三个元素的全排列为:
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
共3 * 2 * 1 = 6种

  • 算法模板(以18年Java组国赛"最大乘积"为例)
//全排列:(递归回溯生成全排列,适用于无重复元素的情况)(考虑第k位,前面已经排定)
//2019决赛最大乘积
//伪代码,作为模板学习
int[] a; int n; f(0);
public static void f(int k){
	if(k == n){	//一种全排列已经产生
		if(check()){
			ans++;
		}
		return;
	}
	for(int i = k; i < n; i++){
		{int t = a[i]; a[i] = a[k]; a[k] = t;}
		f(k + 1);
		{int t = a[i]; a[i] = a[k]; a[k] = t;}
	}
}

3.数据结构

  • 选择合适的数据结构解题可以提高算法效率,减少代码复杂度
  • 若要想取得比较好的成绩, 必须熟悉几种数据结构
//比赛中常用的数据结构(Java)
Hashmap 	//最常用
ArrayList 	//可以替代数组,底层为可动态扩容数组
Queue		//队列,bfs算法时使用
Deque Stack //栈
...

4.String

  • Java组中的比赛最喜欢考的就是字符串的一些操作,如果不是很了解String中的一些方法,自己实现方法会比较耗时。一下列出几种常用方法。若比赛中忘记方法名或者用法,可以直接查看API文档
//String类的常用方法:
boolean	contains(CharSequence s)	//当且仅当此字符串包含指定的char值序列时才返回true。 
int indexOf(int ch)					//返回指定字符在此字符串中第一次出现处的索引。
int length()						//返回此字符串的长度。
String[] split(String regex)		//根据给定正则表达式的匹配拆分此字符串。
String substring(int beginIndex, int endIndex)		//返回一个新字符串,它是此字符串的一个子字符串。(包括beginIndex,不包括endIndex)
char[] toCharArray()				//将此字符串转换为一个新的字符数组。
String valueOf(int i) 				//返回 int参数的字符串 int形式。

5.取模

  • 比赛中很多填空题在题目末尾会说保留后几位数,这就需要通过取模来进行判断
  • 一定得考虑数据的规模,是否会超出整型或者long型范围,最好是每计算一次就进行取模,而不要最后得出结果一起取模
//如保留后四位数,则需要%10000
//往往这种题都会跟随者大量的for循环
for(int i = 0; i < N; i++){
	sum = (sum + n) % 10000;
}

6.深度优先搜索(DFS)和广度优先搜索(BFS)

  • 蓝桥杯比赛中经常会出一些图求最短路径或者可能的路径问题。当然这些题都是非常区分度的题目。曾两年作为填空题的压轴题。若是考场中实在不会写跳过就行。
  • 这两种算法只是一种思想,若要真的能在比赛中合理运用还需要仔细理解这两种算法的思想,切勿死记硬背。
  • 一般求图可能出现多少种路径问题用DFS算法就可以解决,以下是自己总结的模板,不同题目可以根据题目要求进行修改。
//此算法需要用到递归,需要考虑图的大小防止栈溢出
int[][] dir = {{1,0},{-1,0},{0,1},{0,-1}};
int[][] map = new int[n][m];
int[][] modelmap = new int[n][m];//模板
public static void dfs(int x, int y){
	if(x==n&&y==m)
	{
		sum++;
		return;
	}
	for(int i = 0; i < 4; i++){
		int x1 = x + dir[i][0];
		int y1 = y + dir[i][1];
		if(x1<=n&&x1>0&&y1<=m&&y>0){
			if(map[x1][y1]==1 && modelmap!=0){
				modelmap[x1][y1]=0;
				dfs(x1,y1);
				modelmap[x1][y1]=1;
			}
		}
	}
}
  • 检查连通性问题也可以使用DFS算法
public static void dfs(int[][] g, int i, int j){
	g[i][j] = 0;
	if(i - 1 >= 0 && g[i - 1][j] == 1) dfs(g, i - 1, j);
	if(i + 1 <= 2 && g[i + 1][j] == 1) dfs(g, i + 1, j);
	if(j - 1 >= 0 && g[i][j - 1] == 1) dfs(g, i, j - 1);
	if(j + 1 <= 4 && g[i][j + 1] == 1) dfs(g, i, j + 1);
}
  • 一般求图的最短路径问题使用的方法为BFS算法。
class{
	int x;
	int y;
	public Node(int x, int y){
		this.x = x;
		this.y = y;
	}
}
public static int[][] dir = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
public static String[][] ans = new String[n][m]; //方向
public static char[][] arr = new char[n][m];//地图
public static int[][] len = new int[n][m];//长度
public static int[][] vis = new int[n][m];//模板
public static void main(String[] args){
	bfs(0,0);
	System.out.println(len[n][m]);
}
public static void bfs(int x, int y){
	Queue<Node> queue = new LinkedList<>();
	queue.add(new Node(x,y));
	while(!queue.isEmpty()){
		Node node = queue.poll();
		vis[x][y] = 1;
		ans[0][0] = "";
		for(int i = 0; i < 4; i++){
			int x1 = node.x + dir[i][0];
			int y1 = node.y + dir[i][1];
			if(x1<=n&&x1>0&&y1<=m&&y1>0]){
				if(vis[x1][y1]==0&&arr[x1][y1]=='0'){
					vis[x1][y1] = 1;
					len[x1][y1] = len[node.x][node.y]+1;
					ans[x1][y1] = ans[node.x][node.y]+String.valueOf(i);
					queue.add(new Node(x1,y1));
				}
			}
		}
	}
}

7.动态规划

  • 动态规划对于初学算法的同学来说是比较难的算法,在比赛中也会经常有所出现。但是能用动态规划写的题目基本上也可以暴力破解。若是不熟悉动态规划思想可直接暴力破解得部分分。若要冲击国赛比较好的名次的话,这需要仔细的去学习动态规划的思想。
  • 动态规划有多种经典题目,如斐波那契,01背包等,一般使用一维或者二维数组进行模拟。

8.二分法

  • 用于优化代码,可以用来提高检索效率,但用二分法查找需要保证是有序的数组
int r=100001;
int l=1;
int ans=0;
while(l <= r){
	int mid=(l+r)/2;
	if(true && >){
		l=mid+1;
		ans=mid;
	}else{
		r=mid-1;
	}
}

9.博弈问题

  • 此类算法考的不是很多,一般也只是在国赛中出现。有能力的同学可以先了解一下思想,比赛的时候遇到不会那么懵。
//博弈问题简单模板,可根据题意进行更改
f(n, 0, 0)
public static char f(int num, int me, int you){
	if(num < n[0]){	//不够取
		if((me&1)==1&&(you&1)==0)return '+';
		else((me&1)==0&&(you&1)==1)return '-';
		else return '0';
	}
	boolean ping = flase //判断是否平局
	for(int i = 0; i < 3; i++){
		if(num >= n[i]){
			char res = f(num - n[i], you, me + n[i]);
			if(res == '-'){
				return '+';
			}
			if(res == '0'){
				ping = true;
			}
		}
		//如果能走到这行,说明不存在对手输的情况,那么是否存在平的情况
		if(ping)
			return '0';
		else
			return '-';
	}
}

10.大数运算

  • 编程题中尤其喜欢考大数运算,如测试数据超过Java的long型或者C++的longlong型。
  • C++解决则相对复杂一下,需要使用数组模拟
  • Java中则相对简单,使用BigerInteger(大数据运算)或BigDecimal(大浮点数运算)。
  • 若时间充足,则有必要看看题目结尾数据最大规模判断是否需要进行优化,使用大数据运算。如果数据规模不会超出基本类型限制则不需要使用。

总结:

  1. 若想取得不错的名次一定要多刷历年真题!多刷历年真题!多刷历年真题!
  2. 要能总结学习到的算法,做到举一反三。
  3. 对于想要有比较不错奖项的同学一定要仔细学习递归,数据结构及动态规划。
  4. 比赛并没有想象的难,保持好心态,细心写题必能取得好的名次

本文希望可以给正在备考或者以后想要参赛的同学一些帮助。预祝各位都能取得理想的名次。

你可能感兴趣的:(算法,蓝桥杯题解,java)