蓝桥杯练习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 迷宫的解说图:

实验楼pythonnba 实验楼路牌拼写_蓝桥杯

解题思路

这道题是典型的 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 年省赛)

题目描述

小蓝要用七段码数码管来表示一种特殊的文字。

实验楼pythonnba 实验楼路牌拼写_实验楼pythonnba_02

上图给出了七段码数码管的一个图示,数码管中一共有 7段可以发光的二极管,分别标记为 a, b, c, d, e, f, g。

小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。

例如:b发光,其他二极管不发光可以用来表达一种字符。

例如 c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。

例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。

例如:b, f发光,其他二极管不发光则不能用来表达一种字符,因为发光的二极管没有连成一片。

请问,小蓝可以用七段码数码管表达多少种不同的字符?

解题思路

题目要求发光的二极管是相连的,可以用 DFS 或并查集查找连通块。

用字符表示数码管不太方便,改用数字:

实验楼pythonnba 实验楼路牌拼写_c++_03

分 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;
}