第八届蓝桥杯省赛真题题解

2017年蓝桥杯试题解析

不得不说自己还是太菜了,2017年蓝桥杯填空题自己就措手不及了。。

t1标题:迷宫###

X星球的一处迷宫游乐场建在某个小山坡上。
它是由10x10相互连通的小房间组成的。
房间的地板上写着一个很大的字母。
我们假设玩家是面朝上坡的方向站立,则:
L表示走到左边的房间,R表示走到右边的房间,
U表示走到上坡方向的房间,D表示走到下坡方向的房间。
X星球的居民有点懒,不愿意费力思考。
他们更喜欢玩运气类的游戏。这个游戏也是如此!
开始的时候,直升机把100名玩家放入一个个小房间内。
玩家一定要按照地上的字母移动。
迷宫地图如下:
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
请你计算一下,最后,有多少玩家会走出迷宫?
而不是在里边兜圈子。
请提交该整数,表示走出迷宫的玩家数目,不要填写任何多余的内容。

思路

考虑到每一个位置的方向是固定的,所以只要玩家走到之前走过的(已经标记的)的格子上,视为无法走出格子。dfs的出口是玩家走出房间边界,ans++。对每一个格子分别dfs搜索。

代码

#include <iostream>
using namespace std;
string data[10];
int ans;
int vis[10][10];
bool solve(int i, int j) {
    if (i < 0 || i > 9 || j < 0 || j > 9)
        return true;
    if(vis[i][j]==1)
        return false;
    vis[i][j] = 1;
    switch(data[i][j]){
        case 'U':
            return solve(i-1,j);
        case 'D':
            return solve(i+1,j);
        case 'L':
            return solve(i,j-1);
        case 'R':
            return solve(i,j+1);
        default:
            return false;
    }
}
int main() {
    data[0] = "UDDLUULRUL";data[1] = "UURLLLRRRU";
    data[2] = "RRUURLDLRD";data[3] = "RUDDDDUUUU";
    data[4] = "URUDLLRRUU";data[5] = "DURLRLDLRL";
    data[6] = "ULLURLLRDU";data[7] = "RDLULLRDDD";
    data[8] = "UUDDUDUDLL";data[9] = "ULRDLUURRR";
    for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < 10; ++j) {
            memset(vis,0, sizeof(vis));
            if (solve(i, j))
                ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

t2标题:跳蚱蜢

如图所示:

有9只盘子,排成1个圆圈。
其中8只盘子内装着8只蚱蜢,有一个是空盘。
我们把这些蚱蜢顺时针编号为 1~8
每只蚱蜢都可以跳到相邻的空盘中,
也可以再用点力,越过一个相邻的蚱蜢跳到空盘中。
请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列,
并且保持空盘的位置不变(也就是1-8换位,2-7换位,...),至少要经过多少次跳跃?
注意:要求提交的是一个整数,请不要填写任何多余内容或说明文字。

思路

求最少次数,考虑bfs,接下来就是如何设计这个bfs了。首先把圆盘的数字和空格处理成一个字符串,表示当前的状态,如何和目标状态相同,则找到最优答案。考虑每一步的状态转移,空格左右相邻的两个数字都可以和空格互换,为方便空格的定位,而且题目要求空格的位置不变,所以状态中也应该考虑空格的位置。因为要求步数,附加一个参数cnt计数。tips:set去重

#include<iostream>
#include<cstring> 
#include<queue>
#include<string>
#include<set>//去重 
using namespace std;
string start = "012345678";
string target = "087654321";
struct node{
	string a;
	int pos0;
	int cnt;
	node(string a,int pos0,int cnt):a(a),pos0(pos0),cnt(cnt){
	}
	
};
queue<node>que;
void swap(string &str,int a,int b){
	char t=str[a];
	str[a]=str[b];
	str[b]=t;
}
set<string>se;//默认排序 

void fun(string s,int pos,int cnt,int new_pos){
	swap(s,pos,new_pos);
	if(se.find(s)==se.end()){
		se.insert(s);
		que.push(node(s,new_pos,cnt+1)); 
	}
}
int bfs(){
    que.push(node(start,0,0));
    se.insert(start);
    while(!que.empty()){
    	node sta=que.front();
    	if(sta.a==target){
    		return sta.cnt;
		}
		int pos=sta.pos0;
		int new_pos=(pos-1+9)%9;
		fun(sta.a ,sta.pos0,sta.cnt,new_pos);
	    new_pos=(pos+1+9)%9;
		fun(sta.a ,sta.pos0,sta.cnt,new_pos);
		  new_pos=(pos-2+9)%9;
		fun(sta.a ,sta.pos0,sta.cnt,new_pos);
		  new_pos=(pos+2+9)%9;
		fun(sta.a ,sta.pos0,sta.cnt,new_pos);
		que.pop();
	}
	
}
int main(){
	  cout<< bfs()<<endl;
      return 0;
} 

t3标题:魔方状态

二阶魔方就是只有2层的魔方,只由8个小块组成。
如图所示。

小明很淘气,他只喜欢3种颜色,所以把家里的二阶魔方重新涂了颜色,如下:

前面:橙色
右面:绿色
上面:黄色
左面:绿色
下面:橙色
后面:黄色

请你计算一下,这样的魔方被打乱后,一共有多少种不同的状态。

如果两个状态经过魔方的整体旋转后,各个面的颜色都一致,则认为是同一状态。

请提交表示状态数的整数,不要填写任何多余内容或说明文字。

思路

这个题就没有写了。。。
题解传送门

t4标题:方格分隔

6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。

如图:

就是可行的分割法。

试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。
请提交该整数,不要填写任何多余的内容或说明文字。

思路

首先考虑的是T字型,dfs是跑不出来的,那这个题该怎样解决呢?
首先两个部分是关于中心对称的,把坐标(3,3)作为中心点。
可以考虑用dfs跑方格的切割线,标记走过的点,同时标记对称点,但搜索到边界,ans++。考虑四个方向同时搜索到,最后答案除4。

#include <iostream>
#include<cstring>
using namespace std;
int ans=0;
//int dx[4]={0,1,-1,0};
//int dy[4]={-1,0,0,1};
int dire[][2] = {{-1, 0},
                 {1,  0},
                 {0,  -1},
                 {0,  1}};
int vis[7][7];
void dfs(int x,int y){
   if (x == 0 || y == 0 || x == 6 || y == 6) {
        ans++;
        return;
    }
	vis[x][y]=1;
	vis[6-x][6-y]=1;
	for(int i=0;i<4;i++){
		int nx=x+dire[i][0],ny=y+dire[i][1];
		if(nx>=0&&nx<=6&&ny>=0&&ny<=6&&!vis[nx][ny]){
			dfs(nx,ny);
				vis[nx][ny]=0;
		vis[6-nx][6-ny]=0;
		}
	}

} 
int main() {
    dfs(3, 3);
    cout << ans / 4 << endl;
    return 0;
}

代码填空题较为简单,在此不写了

t7正则问题

考虑一种简单的正则表达式:
只由 x ( ) | 组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

输入

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

输出

这个正则表达式能接受的最长字符串的长度。

例如,
输入:
((xx|xxx)x|(x|xx))xx

程序应该输出:
6
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

思路

这个题开始完全看不懂题意。题意是:|表示或,左右取一个较大的连续的x,例如:xxx|xx就是3,最后问最大的连续的是多少,()有最高优先级。求连续的x的个数。运用递归,处理(,求解子问题,加深一层,遇到),退出一层。这个题有点类似表达式的处理,自己也是没能写出来。

代码

#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
char s[100];
int len;
int pos;
/*求出当前字符串,自当前下标到结束能匹配的字符串的长度*/
int f() {
    int m = 0;
    int tmp = 0;//用于保存连续的x的数量
    while (pos < len) {
        if (s[pos] == '(') {
            pos++;
            tmp += f();//等待后面的结果并累加到ans
        } else if (s[pos] == 'x') {//
            pos++;
            tmp++;
        } else if (s[pos] == '|') {
            pos++;
            m = max(m, tmp);
            tmp = 0;
        } else if (s[pos] == ')') {
            pos++;
            m = max(m, tmp);
            return m;
        }
    }
    m = max(m, tmp);
    return m;
}
int main() {
    scanf("%s", &s);
    len = strlen(s);
    int ans = f();
    printf("%d
", ans);
    return 0;
}

t8包子凑数

小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有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
CPU消耗 < 1000ms

思路

之前蓝桥杯出现一个题,给定两个数a,b求出他们最大不能凑数的数。这个题思路就是如果他们互质,那么这个数是ab-a-b,否则就是INF。那么对于这个题,计算不能凑数的个数,如何他们之间的gcd!=1,则是INF,否则这样考虑:问题规模比较小,最大不能凑数的数肯定小于10000
。所以用O(n
n*n)的规模可以在时限下面解决。
tips:对于每个数0~10000,用vis数组标记他们是否可以凑出,对以及扩展的数不断加上其它的数,来改变vis数组标记,最后遍历vis数组即可。

代码

#include<iostream>
using namespace std;
int gcd(int a, int b) {
	return a % b == 0 ? b : gcd(b, a%b);
}

int a[101];
bool f[10101];
int gc;
int ans = 0;
int main() {
	int n;
	cin >> n;
	f[0] = true;
	for (int i = 0; i<n; i++) {
		cin >> a[i];
		if (i == 0)gc = a[i];
		else gc = gcd(a[i], gc);
		for (int j = 0; j < 10000; ++j) {
			if (f[j])
				f[j + a[i]] = true;
		}
	}
	if (gc != 1) {
		cout << "INF
";

	}
	else {
		for (int i = 0; i<10000; i++)
			if (!f[i])ans++;
		cout << ans << endl;
	}
	
	return 0;
}

t9分巧克力

儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

1. 形状是正方形,边长是整数
2. 大小相同

例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
输入保证每位小朋友至少能获得一块1x1的巧克力。
输出
输出切出的正方形巧克力最大可能的边长。
样例输入:
2 10
6 5
5 6
样例输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

思路

较为明显的二分+check,二分可能的边长

代码

#include <stdio.h>
#include <cstring>
#include <algorithm>
#include<iostream> 
using namespace std;
const int N=1e5+10;
struct node{
	int x,y;
}a[N];
int n,k;
bool check(int w){
	int ans=0;
	for(int i=0;i<n;i++){
		ans+=(a[i].x/w)*(a[i].y/w);
	}
	return ans>=k;
}
int ans;
int main(){

	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>a[i].x >>a[i].y;
	}
	int l=1,r=N;
	int mid; 
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid)){
			l=mid+1;
			ans=mid;
		}
		else r=mid-1;
	}
	cout<<ans<<endl;//不能输出mid 
	return 0;
}

t10油漆面积

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

线段树加扫描线的模板题,手写不出线段树。

题解传送门

不疯魔不成活
原文地址:https://www.cnblogs.com/gzr2018/p/10577952.html