第六届蓝桥杯大赛个人赛决赛(软件类) C++A组真题题解
文章目录
- 题目链接
- A组真题
- 题目结构
- 第一题 方格填数
- 第二题 四阶幻方
- 第三题 显示二叉树
- 第四题 穿越雷区
- 第五题 切开字符串
- 第六题 铺瓷砖(待补)
题目链接
A组真题
题目结构
题目 | 类型 | 分值 |
---|---|---|
第一题 | 结果填空 | 19分 |
第二题 | 结果填空 | 25分 |
第三题 | 代码填空 | 31分 |
第四题 | 程序设计 | 41分 |
第五题 | 程序设计 | 75分 |
第六题 | 程序设计 | 99分 |
第一题 方格填数
问题重现
在2行5列的格子中填入1到10的数字。
要求:
相邻的格子中的数,右边的大于左边的,下边的大于上边的。
如下图所示的2种,就是合格的填法。
请你计算一共有多少种可能的方案。
请提交该整数,不要填写任何多余的内容(例如:说明性文字)。解题思路
对于这种类型的题,我们有两种方法可以解决。一种是暴力全排列,一种是dfs搜索。对于暴力全排列枚举所有情况,这里显然是可以的,因为只有101010个空,也就是A1010A_{10}^{10}A1010,肯定能跑出来。而dfsdfsdfs显然更快,因为我们在搜索过程中可以即是排除不可能的路径,即剪枝。这里给出dfsdfsdfs搜索的一般思路:
标记数组
放数的数组int check(参数)
{if(满足条件)return 1;elsereturn 0;
}//这个dfs合不合格,能不能继续下一个去做每一步
int dfs(int step)
{判断边界;{相应操作;}尝试每一种可能{满足check条件{标记;进行下一步递归;恢复初始状态(取消标记),方便回溯}}
}
如果能够理解这个,那么就跟做模板题一样。该题的主要细节就是判断条件,这跟你的元素放置位置和搜索顺序有关。具体看代码。
- 暴力全排列代码
/**
* @filename:方格填数.cbp
* @Author : pursuit
* @Blog:unique_pursuit
* @email: 2825841950@qq.com
* @Date : 2021-03-14-20.36.56
*/
#include<bits/stdc++.h>using namespace std;typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;int a[]={1,2,3,4,5,6,7,8,9,10};//按字典升序。方便全排列不遗漏
//全排列所有结果,判断合格方格。答案42.
void solve(){int result=0;do{bool flag=true;for(int i=0;i<4;i++){if(a[i]>a[i+1]){flag=false;break;}}if(!flag)continue;for(int i=5;i<9;i++){if(a[i]>a[i+1]){flag=false;break;}}if(!flag)continue;for(int i=0;i<=4;i++){if(a[i]>a[i+5]){flag=false;break;}}if(!flag)continue;result++;}while(next_permutation(a,a+10));cout<<result<<endl;
}
int main(){solve();return 0;
}
- dfs搜索代码
/**
* @filename:方格填数.cbp
* @Author : pursuit
* @Blog:unique_pursuit
* @email: 2825841950@qq.com
* @Date : 2021-03-14-20.47.27
*/
#include<bits/stdc++.h>using namespace std;typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;//dfs,这里有个细节就是我们怎么填这个方格,为了让相邻数与其编号之间有联系,我们从上往下开始填。若为奇数编号,说明在上边。
bool vis[11];//vis[i]表示数字i是否被填充过。
int num[11];//代表我们的方格。
int result=0;//统计方案数。
bool check(int step,int x){if(step%2){if(x>num[step-2]){return true;}}else{if(x>num[step-1]&&x>num[step-2]){return true;}}return false;
}
void dfs(int step){//step代表我们此时填的第step的元素。if(step>10){//说明10个数已经填完了。result++;return;}for(int i=1;i<=10;i++){//判断是否符合条件。if(!vis[i]&&check(step,i)){vis[i]=true;num[step]=i;dfs(step+1);vis[i]=false;}}
}
void solve(){dfs(1);cout<<result<<endl;
}
int main(){solve();return 0;
}
- 答案
424242。
第二题 四阶幻方
问题重现
把1~16的数字填入4x4的方格中,使得行、列以及两个对角线的和都相等,
满足这样的特征时称为:四阶幻方。
四阶幻方可能有很多方案。如果固定左上角为1,请计算一共有多少种方案。
比如:
1 2 15 16
12 14 3 5
13 7 10 4
8 11 6 9
以及:
1 12 13 8
2 14 7 11
15 3 10 6
16 5 4 9
就可以算为两种不同的方案。
请提交左上角固定为1时的所有方案数字,
不要填写任何多余内容或说明文字。解题思路
这道题和第一题一样,那么我们是不是也有两种方法来做这题呢?先看暴力全排列,我们算一下时间复杂度,高达A1515=2004310016A_{15}^{15}=2004310016A1515=2004310016,我自己也亲测等了好久也跑不出来,因为全排列会枚举所有的情况,不会剪枝,在这种情况下是非常不友好的,所以我们只能考虑dfs搜索剪枝了。怎么搜索呢?我们从行开始搜索,当每一次行或列形成的时候我们就进行判断是否符合,(由于行列和要相等,说明其值为方格数总和的四分之一,即343434。)同时在dfsdfsdfs中,一定要注意标记状态,同时也一定要注意还原状态,这样才能保证每一条路径都搜索过。清楚了这些,那处理好其余的细节这道题目就出来了。代码
/**
* @filename:四阶幻方.cbp
* @Author : pursuit
* @Blog:unique_pursuit
* @email: 2825841950@qq.com
* @Date : 2021-03-14-21.36.17
*/
#include<bits/stdc++.h>using namespace std;typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;//dfs
//易知,行,列以及对角线上的和为34,因为其为1到16的和除以4.
bool vis[17];//vis[i]表示数字i是否已经被填充。
int a[4][4];//方格。
int result=0;
bool check(int x,int y){if(x<3){//说明方格暂未成型,我们只能判断所在行是否成型。if(y<3)return true;if(a[x][0]+a[x][1]+a[x][2]+a[x][3]==34){return true;}return false;}else{//开始判断y。if(y==0){//说明第一列和对角线都已成型。if(a[0][0]+a[1][0]+a[2][0]+a[3][0]!=34||a[0][3]+a[1][2]+a[2][1]+a[3][0]!=34){return false;}}else if(y==1||y==2){//判断第二列和第三列的和是不是34.if(a[0][y]+a[1][y]+a[2][y]+a[3][y]!=34){return false;}}else{if(a[0][3]+a[1][3]+a[2][3]+a[3][3]!=34||a[0][0]+a[1][1]+a[2][2]+a[3][3]!=34){return false;}}return true;}
}
void dfs(int x,int y){//(x,y)表示的是我们当前正在填充的数坐标。if(x==4){//说明方格已经填完。result++;return;}for(int i=1;i<=16;i++){if(!vis[i]){vis[i]=true;a[x][y]=i;if(check(x,y)){if(y<3){dfs(x,y+1);}else{//说明需要换行。dfs(x+1,0);}}//还原标记。vis[i]=false;}}
}
void solve(){//题目规定a[0][0]=1.vis[1]=true;a[0][0]=1;dfs(0,1);cout<<result<<endl;
}
int main(){solve();return 0;
}
- 答案
416416416。
第三题 显示二叉树
- 问题重现
排序二叉树的特征是:
某个节点的左子树的所有节点值都不大于本节点值。
某个节点的右子树的所有节点值都不小于本节点值。
为了能形象地观察二叉树的建立过程,小明写了一段程序来显示出二叉树的结构来。
对于程序中的测试数据,应该显示出:
请分析程序逻辑,填写划线部分缺失的代码。
注意,只填写缺少的部分,不要填写已有的代码或符号,也不要加任何说明文字。
#include <stdio.h>
#include <string.h>
#define N 1000
#define HEIGHT 100
#define WIDTH 1000struct BiTree
{int v;struct BiTree* l;struct BiTree* r;
};int max(int a, int b)
{return a>b? a : b;
}struct BiTree* init(struct BiTree* p, int v)
{p->l = NULL;p->r = NULL;p->v = v;return p;
}void add(struct BiTree* me, struct BiTree* the)
{if(the->v < me->v){if(me->l==NULL) me->l = the;else add(me->l, the);}else{if(me->r==NULL) me->r = the;else add(me->r, the);}
}//获得子树的显示高度
int getHeight(struct BiTree* me)
{int h = 2;int hl = me->l==NULL? 0 : getHeight(me->l);int hr = me->r==NULL? 0 : getHeight(me->r);return h + max(hl,hr);
}//获得子树的显示宽度
int getWidth(struct BiTree* me)
{char buf[100];sprintf(buf,"%d",me->v);int w = strlen(buf);if(me->l) w += getWidth(me->l);if(me->r) w += getWidth(me->r);return w;
}int getRootPos(struct BiTree* me, int x){return me->l==NULL? x : x + getWidth(me->l);
}//把缓冲区当二维画布用
void printInBuf(struct BiTree* me, char buf[][WIDTH], int x, int y)
{int p1,p2,p3,i;char sv[100];sprintf(sv, "%d", me->v);p1 = me->l==NULL? x : getRootPos(me->l, x);p2 = getRootPos(me, x);p3 = me->r==NULL? p2 : getRootPos(me->r, p2+strlen(sv));buf[y][p2] = '|';for(i=p1; i<=p3; i++) buf[y+1][i]='-';for(i=0; i<strlen(sv); i++) buf[y+1][p2+i]=sv[i];if(p1<p2) buf[y+1][p1] = '/';if(p3>p2) buf[y+1][p3] = '\\';if(me->l) printInBuf(me->l,buf,x,y+2);if(me->r) ____________________________________; //填空位置
}void showBuf(char x[][WIDTH])
{int i,j;for(i=0; i<HEIGHT; i++){for(j=WIDTH-1; j>=0; j--){if(x[i][j]==' ') x[i][j] = '\0';else break;}if(x[i][0]) printf("%s\n",x[i]);else break;}
}void show(struct BiTree* me)
{char buf[HEIGHT][WIDTH];int i,j;for(i=0; i<HEIGHT; i++)for(j=0; j<WIDTH; j++) buf[i][j] = ' ';printInBuf(me, buf, 0, 0);showBuf(buf);
}int main()
{ struct BiTree buf[N]; //存储节点数据int n = 0; //节点个数init(&buf[0], 500); n++; //初始化第一个节点add(&buf[0], init(&buf[n++],200)); //新的节点加入树中add(&buf[0], init(&buf[n++],509));add(&buf[0], init(&buf[n++],100));add(&buf[0], init(&buf[n++],250));add(&buf[0], init(&buf[n++],507));add(&buf[0], init(&buf[n++],600));add(&buf[0], init(&buf[n++],650));add(&buf[0], init(&buf[n++],450));add(&buf[0], init(&buf[n++],440));add(&buf[0], init(&buf[n++],220));show(&buf[0]); return 0;
}
解题思路
对于这种类型的题,尤其是这一道,虽然代码非常长,但我们发现其实对我们有用的就那几个打印的函数。在填空上一行代码,这是打印的左子树,我们发现,其中填充的参数为:子树结点,二维画布buf
,还有就是结点坐标了。我们要知道的是y代表的是层数,左右子树层数肯定是相同的,所以是x不一样,而p2是中间结点位置,sv为结点值,也就是结点长度,观察图中即可得,如果不填确定,我们可以打印看看是否与原图一致。答案
printInBuf(me->r,buf,p2+strlen(sv),y+2)
第四题 穿越雷区
问题重现
X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区
才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量
特征),怎样走才能路径最短?
已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号
或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
左右上
坦克车只能水平或垂直方向上移动到相邻的区。
数据格式要求:
输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,
中间用空格分开。
A,B都只出现一次。
要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1
例如:
用户输入:
5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
则程序应该输出:
10
资源约定:
峰值内存消耗 < 512M
CPU消耗 < 1000ms解题思路
标准的bfsbfsbfs模板题,我们做这种题有步骤:
1.将图用二维数组表示。
2.将起点加入队列,并标记其入队状态。
3.取队头节点,找到队头节点相邻的可访问的节点,加入队列(加入的顺序根据你查找的上下左右四个方向的顺序决定)。并标记结点入队状态。
4.将队头元素出队。
5.重复3,4步骤,直到找到终点。那么这道题我们也同样按这样的步骤来写。要注意的点就是,在输入的时候应该要以字符型输入,而不是字符串,因为题目中是以空格分割的。
代码
/**
* @filename:穿越雷区.cbp
* @Author : pursuit
* @Blog:unique_pursuit
* @email: 2825841950@qq.com
* @Date : 2021-03-15-18.55.57
*/
#include<bits/stdc++.h>using namespace std;typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;int n;
char graph[105][105];
bool vis[105][105];//判断此点是否又被走过。
int go[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//模拟行走方向。
int ax,ay;//存储A的位置。
typedef struct Node{int x,y,step;//step表示已经移动的次数。Node & operator=(const Node&a){x=a.x,y=a.y,step=a.step;}
}node;
void bfs(){queue<node> q;memset(vis,false,sizeof(vis));node head,temp;head.x=ax,head.y=ay,head.step=0;q.push(head);vis[ax][ay]=true;
// for(int i=1;i<=n;i++){// for(int j=1;j<=n;j++){// cout<<graph[i][j];
// j==n?cout<<endl:cout<<" ";
// }
// }while(!q.empty()){head=q.front();
// cout<<"x:"<<head.x<<" y:"<<head.y<<" step:"<<head.step<<endl;q.pop();for(int i=0;i<4;i++){temp.x=head.x+go[i][0],temp.y=head.y+go[i][1],temp.step=head.step+1;if(temp.x<1||temp.x>n||temp.y<1||temp.y>n||vis[temp.x][temp.y]||graph[temp.x][temp.y]==graph[head.x][head.y])continue;if(graph[temp.x][temp.y]=='B'){cout<<temp.step<<endl;return;}vis[temp.x][temp.y]=true;q.push(temp);}}cout<<-1<<endl;return;
}
void solve(){bfs();
}
int main(){while(cin>>n){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>graph[i][j];//记录起点坐标。if(graph[i][j]=='A'){ax=i,ay=j;}}}solve();}return 0;
}
第五题 切开字符串
问题重现
Pear有一个字符串,不过他希望把它切成两段。
这是一个长度为N(<=10^5)的字符串。
Pear希望选择一个位置,把字符串不重复不遗漏地切成两段,
长度分别是t和N-t(这两段都必须非空)。
Pear用如下方式评估切割的方案:
定义“正回文子串”为:长度为奇数的回文子串。
设切成的两段字符串中,前一段中有A个不相同的正回文子串,
后一段中有B个不相同的非正回文子串,则该方案的得分为A×BA\times BA×B。
注意,后一段中的B表示的是:“…非正回文…”,
而不是: “…正回文…”。
那么所有的切割方案中,A×BA\times BA×B的最大值是多少呢?
【输入数据】
输入第一行一个正整数N(<=10^5)
接下来一行一个字符串,长度为N。该字符串仅包含小写英文字母。
【输出数据】
一行一个正整数,表示所求的A*B的最大值。
【样例输入】
10
bbaaabcaba
【样例输出】
38
【数据范围】
对于20%的数据,N<=100
对于40%的数据,N<=1000
对于100%的数据,N<=10^5
资源约定:
峰值内存消耗 < 512M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。解题思路
对于这道题,我们可以枚举其分割点位置,也就是前串的长度,那么后串的长度也自然得知。我们同样需要两个函数一个计算正回文子串的数量,一个是非正回文子串的数量。这里需要用到mapmapmap去重。对于字符串分割,我们可以使用string
类内置的substr
方法。具体看代码。代码
/**
* @filename:穿越雷区.cbp
* @Author : pursuit
* @Blog:unique_pursuit
* @email: 2825841950@qq.com
* @Date : 2021-03-15-18.55.57
*/
#include<bits/stdc++.h>using namespace std;typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+5;
const int mod=1e9+7;int n;
char graph[105][105];
bool vis[105][105];//判断此点是否又被走过。
int go[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//模拟行走方向。
int ax,ay;//存储A的位置。
typedef struct Node{int x,y,step;//step表示已经移动的次数。Node & operator=(const Node&a){x=a.x,y=a.y,step=a.step;}
}node;
void bfs(){queue<node> q;memset(vis,false,sizeof(vis));node head,temp;head.x=ax,head.y=ay,head.step=0;q.push(head);vis[ax][ay]=true;
// for(int i=1;i<=n;i++){// for(int j=1;j<=n;j++){// cout<<graph[i][j];
// j==n?cout<<endl:cout<<" ";
// }
// }while(!q.empty()){head=q.front();
// cout<<"x:"<<head.x<<" y:"<<head.y<<" step:"<<head.step<<endl;q.pop();for(int i=0;i<4;i++){temp.x=head.x+go[i][0],temp.y=head.y+go[i][1],temp.step=head.step+1;if(temp.x<1||temp.x>n||temp.y<1||temp.y>n||vis[temp.x][temp.y]||graph[temp.x][temp.y]==graph[head.x][head.y])continue;if(graph[temp.x][temp.y]=='B'){cout<<temp.step<<endl;return;}vis[temp.x][temp.y]=true;q.push(temp);}}cout<<-1<<endl;return;
}
void solve(){bfs();
}
int main(){while(cin>>n){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>graph[i][j];//记录起点坐标。if(graph[i][j]=='A'){ax=i,ay=j;}}}solve();}return 0;
}
第六题 铺瓷砖(待补)
- 问题重现
为了让蓝桥杯竞赛更顺利的进行,主办方决定给竞赛的机房重新铺放瓷砖。机房可以看成一个n*m的矩形,而这次使用的瓷砖比较特别,有两种形状,如下图所示。在铺放瓷砖时,可以旋转。
主办方想知道,如果使用这两种瓷砖把机房铺满,有多少种方案。
【输入格式】
输入的第一行包含两个整数,分别表示机房两个方向的长度。
【输出格式】
输出一个整数,表示可行的方案数。这个数可能很大,请输出这个数除以65521的余数。
【样例输入1】
4 4
【样例输出1】
2
【样例说明1】
这两种方案如下下图所示:
【样例输入2】
2 6
【样例输出2】
4
【数据规模与约定】
对于20%的数据,1<=n, m<=5。
对于50%的数据,1<=n<=100,1<=m<=5。
对于100%的数据,1<=n<=10^15,1<=m<=6。
资源约定:
峰值内存消耗 < 512M
CPU消耗 < 5000ms
第六届蓝桥杯大赛个人赛决赛(软件类) C++A组真题题解相关推荐
- 穿越雷区第六届蓝桥杯大赛个人赛决赛(C语言A组)第四题
标题:穿越雷区 X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废. 某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径 ...
- 第六届蓝桥杯大赛个人赛决赛(C/C++大学B组)
第六届蓝桥杯大赛个人赛决赛(C/C++大学B组) 第一题 积分之迷(15分) 小明开了个网上商店,卖风铃.共有3个品牌:A,B,C. 为了促销,每件商品都会返固定的积分. 小明开业第一天收到了三笔订单 ...
- 第六届蓝桥杯大赛个人赛决赛(软件类)真题-Java语言B组
目录 1.分机号 2.五星填数 3.显示二叉树 4.穿越雷区 5.表格计算 6.铺瓷砖 1.分机号 X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位 ...
- 第六届蓝桥杯大赛个人赛决赛(软件类)真题 Java语言B组 答案
标题:分机号 X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位.比如: 751,520,321 都满足要求,而, 766,918,201 就不符合要 ...
- 第六届蓝桥杯大赛个人赛决赛(软件类)真题
分号机 import java.io.IOException; class MC{public void run(){int cnt = 0;for (int i = 9; i >= 0; i- ...
- 第六届蓝桥杯大赛个人赛省赛Java B组真题
文章目录 第六届蓝桥杯大赛个人赛省赛Java B组真题 1. 三角形面积(结果填空) 2. 立方自变身(结果填空) 3. 三羊献瑞(结果填空) 4. 循环节长度(代码填空) 5. 九数组分数(代码填空 ...
- 【蓝桥杯】第六届蓝桥杯大赛个人赛省赛(软件类) Java大学C组 -题目与答案
第六届蓝桥杯大赛个人赛省赛(软件类) Java大学C组 -题目与答案 1.结果填空(满分3分) 2.结果填空(满分5分) 3.结果填空(满分9分) 4.代码填空(满分11分) 5.代码填空(满分15分 ...
- 第六届蓝桥杯大赛个人赛省赛(软件类) Java 大学B组
好久没更新过博客了,就从蓝桥杯省赛开始更新吧. 第一题: 三角形面积 如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文 ...
- 第七届蓝桥杯大赛个人赛决赛(软件类)真题 Java语言B组 答案
以下代码纯自想自打,如有误,请提出,如可简,请告之,谢谢大家了. 蓝桥杯辅助资料 真题下载 1 愤怒小鸟 X星球愤怒的小鸟喜欢撞火车! 一根平直的铁轨上两火车间相距 1000 米 两火车 (不妨称A和 ...
最新文章
- JavaScriptjQuery.事件流
- SpringQuartz定时任务调度器
- webpack原理探究 打包优化
- mysql 5.7.13安装_安装MySQL 5.7.13
- 红歌合唱之团结就是力量
- spring eureka集群+spring boot 微服务,容器化部署示例
- 推荐一个最近开源的Matting工具箱
- mysql-5.7.17的最新安装教程
- Flask知识点查阅
- Node 中用 ESLint 验证代码
- Top的VIRT是什么
- win10更新过后导致某些字体被损坏
- 怎么彻底卸载cad2017_如何彻底卸载AutoCAD
- php自学笔记四扫雷完成
- FlashFXP使用及连接不上的错误问题
- linux裸设备详解,Linux裸设备管理详解(原创)
- Citrix PVS架构和工作原理
- 玩烂vue之vue练手项目
- Redis key前缀的设计与使用
- 浅谈从项目型公司到产品型公司的转型