本文已参与「新人创作礼」活动,一起开启掘金创作之路。
蓝桥杯练习005
蓝桥杯真题:门牌制作(2020 年省赛)
题目描述
小蓝要为一条街的住户制作门牌号。
这条街一共有 2020位住户,门牌号从 11 到 2020编号。
小蓝制作门牌的方法是先制作 0到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 1 个字符 0,2 个字符 1,1 个字符 7。
请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?
解题思路
判断每个数字中有几个 2,然后把所有数字中 2 的个数加起来。
代码
#include <iostream>
using namespace std;
int main()
{
int cnt=0;
int a[4];
for(int i=1;i<=2020;i++)
{
int j=i;
int k=0;
while(j){
a[k++]=j%10;
j/=10;
}
for(int i=0;i<k;i++)
if(a[i]==2)
cnt++;
}
cout<<cnt<<endl;
return 0;
}
蓝桥杯真题:卡片(2021 年省赛)
题目描述
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。小蓝想知道自己能从 1 拼到多少。例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1 拼到多少?提示:建议使用计算机编程解决问题。
解题思路
记录每一种卡片的数量,用到后数量减少,当有用到某张卡片并且没有剩余卡片可使用的时候终止循环,输出上一次的值。
代码
#include <iostream>
using namespace std;
int main()
{
int a[10];
for(int i=0;i<10;i++)
a[i]=2021;//每张卡片的数量
for(int i=1;;i++)//不知道循环多少次,省略,会无限循环
{
int tmp=i;
while(tmp){
if(a[tmp%10]==0){//当有一张卡片没有剩余的时候终止循环,输出上一个结果
cout<<i-1<<endl;
return 0;
//exit(0);
}
a[tmp%10]--;
tmp/=10;
}
}
return 0;
}
蓝桥杯真题:迷宫(2017 年省赛)
题目描述
X 星球的一处迷宫游乐场建在某个小山坡上。它是由 10 ×10 相互连通的小房间组成的。
房间的地板上写着一个很大的字母。我们假设玩家是面朝上坡的方向站立,则:
- L 表示走到左边的房间,
- R 表示走到右边的房间,
- U 表示走到上坡方向的房间,
- D 表示走到下坡方向的房间。
X 星球的居民有点懒,不愿意费力思考。他们更喜欢玩运气类的游戏。这个游戏也是如此!
开始的时候,直升机把 100 名玩家放入一个个小房间内。玩家一定要按照地上的字母移动。
迷宫地图如下:
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
请你计算一下,最后,有多少玩家会走出迷宫,而不是在里边兜圈子?
如果你还没明白游戏规则,可以参看下面一个简化的 4x4 迷宫的解说图:
解题思路
这道题是典型的 DFS
可以直接数,从左往右数,从上往下数,约 2 分钟就能数完。数出来的结果见下面,小写字母上的人能走出来。
uDDLuulrul
uURLLLrrru
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLrdU
RDLULLrddd
UUddUDudll
ULrdlUurrr
代码
#include <iostream>
using namespace std;
char a[10][10]={
'U','D','D','L','U','U','L','R','U','L',
'U','U','R','L','L','L','R','R','R','U',
'R','R','U','U','R','L','D','L','R','D',
'R','U','D','D','D','D','U','U','U','U',
'U','R','U','D','L','L','R','R','U','U',
'D','U','R','L','R','L','D','L','R','L',
'U','L','L','U','R','L','L','R','D','U',
'R','D','L','U','L','L','R','D','D','D',
'U','U','D','D','U','D','U','D','L','L',
'U','L','R','D','L','U','U','R','R','R',
}; //定义字符数组,表示地图
int main()
{
int temp=0,i1,j1,b; //定义相关变量,统计走出的人数以及相关判断量
/*通过遍历数组的每一个成员,逐个逐个判断每一个人能否走出迷宫*/
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
i1=i;j1=j;b=0;
B:
switch(a[i1][j1])
{
case 'U': i1--; //如果地板上字母是U则往上走一步,即数组的行增加一行
if(i1<0){
temp++; //如果行数小于零了,则表示人走出来了,则走出的人数加1,下同
break;
}
else {
b++;
if(b>100) break; //如果此人在这张地图已经走了一百步了,那么我们完全可以判断他在兜圈了,则进入下一个的判断,下同
goto B;
}
case 'D': i1++; //如果地板上字母是D则往下走一步,即数组的行减一行
if(i1>=10){
temp++;
break;
}
else {
b++;
if(b>100) break;
goto B;
}
case 'L': j1--; //如果地板上字母是L则往左走一步,即数组的列减一行
if(j1<0){
temp++;
break;
}
else {
b++;
if(b>100) break;
goto B;
}
case 'R': j1++; //如果地板上字母是R则往左走一步,即数组的列加一行
if(j1>=10){
temp++;
break;
}
else {
b++;
if(b>100) break;
goto B;
}
}
}
}
cout<<temp<<endl;
return 0;
}
#include <iostream>
using namespace std;
#include<vector>
#include<string>
int ans;
vector<vector<char>>vec={
{'U','D','D','L','U','U','L','R','U','L'},
{'U','U','R','L','L','L','R','R','R','U'},
{'R','R','U','U','R','L','D','L','R','D'},
{'R','U','D','D','D','D','U','U','U','U'},
{'U','R','U','D','L','L','R','R','U','U'},
{'D','U','R','L','R','L','D','L','R','L'},
{'U','L','L','U','R','L','L','R','D','U'},
{'R','D','L','U','L','L','R','D','D','D'},
{'U','U','D','D','U','D','U','D','L','L'},
{'U','L','R','D','L','U','U','R','R','R'}};
bool vis[100][100];
void dfs(int x,int y)
{
if(vis[x][y] == true)//是否访问过
return;
if(x<0||y<0||x>=vec.size() || y>=vec[x].size())
{
ans++;
return;
}
switch (vec[x][y])//判断每一种情况
{
case 'U':
vis[x][y]= true;dfs(x-1,y);vis[x][y]= false;break;
case 'L':
vis[x][y]= true;dfs(x,y-1);vis[x][y]= false;break;
case 'R':
vis[x][y]= true;dfs(x,y+1);vis[x][y]= false;break;
case 'D':
vis[x][y]= true;dfs(x+1,y);vis[x][y]= false;break;
default:return;
}
}
void findPath()//寻找
{
for(int i=0;i<vec.size();i++)
for(int j=0;j<vec[i].size();j++)
dfs(i,j);
}
int main()
{
findPath();
cout<<ans<<endl;
}
#include <iostream>
using namespace std;
int cnt;
bool vis[11][11];
char map[10][10]={
'U','D','D','L','U','U','L','R','U','L',
'U','U','R','L','L','L','R','R','R','U',
'R','R','U','U','R','L','D','L','R','D',
'R','U','D','D','D','D','U','U','U','U',
'U','R','U','D','L','L','R','R','U','U',
'D','U','R','L','R','L','D','L','R','L',
'U','L','L','U','R','L','L','R','D','U',
'R','D','L','U','L','L','R','D','D','D',
'U','U','D','D','U','D','U','D','L','L',
'U','L','R','D','L','U','U','R','R','R'
};
void dfs(int i,int j)
{
if(vis[i][j])return;
if(i<0||j<0||i>=10||j>=10)
{
cnt++;
return;
}
switch(map[i][j]){
case 'U':vis[i][j]=true;dfs(i-1,j);vis[i][j]=false;break;
case 'R':vis[i][j]=true;dfs(i,j+1);vis[i][j]=false;break;
case 'D':vis[i][j]=true;dfs(i+1,j);vis[i][j]=false;break;
case 'L':vis[i][j]=true;dfs(i,j-1);vis[i][j]=false;break;
default:return;
}
}
int main()
{
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
dfs(i,j);
}
}
cout<<cnt<<endl;
return 0;
}
蓝桥杯真题:七段码(2020 年省赛)
题目描述
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7段可以发光的二极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。
例如:b发光,其他二极管不发光可以用来表达一种字符。
例如 c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
解题思路
题目要求发光的二极管是相连的,可以用 DFS 或并查集查找连通块。
用字符表示数码管不太方便,改用数字:
分 7 种情况:
- 亮一个灯:有 7 种情况,1、2、3、4、5、6、7;
- 亮两个灯:有 12、13、23、24、25、…等等;
- 亮三个灯:有 123、124、125、134、136、234、257…等等;
- 亮四个灯,这时不要直接数四个灯,情况与灭三个灯是等价的:灭 123、灭 124…等等;
- 亮五个灯,与灭两个灯等价:灭 12、灭 13、灭 14、…等等;
- 亮六个灯,与灭一个灯等价,有 7 种情况;
- 亮七个灯,有 1 种情况。
- 对以上所有情况求和。
代码
dfs搜索所有状态,判断每种状态可不可行。判断的方法是把每条灯管当作一个节点,编号,连边建图,对搜索出的亮灯方案使用并查集判断点亮的灯管是否在同一个集合。
#include<bits/stdc++.h>
using namespace std;
const int N=10;
int use[N],ans,e[N][N],fa[N];
void init(){
/*
连边建图,e[i][j]==1表示i和j相邻
a b c d e f g
1 2 3 4 5 6 7
*/
e[1][2]=e[1][6]=1;
e[2][1]=e[2][7]=e[2][3]=1;
e[3][2]=e[3][4]=e[3][7]=1;
e[4][3]=e[4][5]=1;
e[5][4]=e[5][6]=e[5][7]=1;
e[6][1]=e[6][5]=e[6][7]=1;
}
int find(int u){if(fa[u]==u)return u;fa[u]=find(fa[u]);return fa[u];}//并查集
void dfs(int d){
if(d>7){
/* 并查集判是否在同一集合 */
for(int i=1;i<=7;i++)fa[i]=i;//初始化父亲集合
for(int i=1;i<=7;i++)//遍历所有边集
for(int j=1;j<=7;j++)
if(e[i][j]&&use[i]&&use[j]){
int fx=find(i),fy=find(j);
if(fx!=fy)fa[fx]=fy;//如果不在同一集合,合并
}
int k=0;
for(int i=1;i<=7;i++)
if(use[i]&&fa[i]==i)k++;
if(k==1)ans++;//如果所有亮灯都属于同一个集合
return;
}
use[d]=1;//打开d这个灯,继续开关下一个灯
dfs(d+1);
use[d]=0;//关闭d这个灯,继续开关下一个灯
dfs(d+1);
}
int main(){
init();
dfs(1);
cout<<ans;
}