首页 > 其他分享 >七段码(蓝桥杯)

七段码(蓝桥杯)

时间:2024-03-30 23:30:39浏览次数:39  
标签:连通 int 二极管 蓝桥 start 发光 七段

文章目录

七段码

题目描述

小蓝要用七段码数码管来表示一种特殊的文字。
在这里插入图片描述

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

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

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

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

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

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

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

答案:80

分析

手工求解:容易遗漏,本题不宜采用。

编程求解:有多种方法

方法一:状态压缩+枚举+构图(以二极管为顶点)+DFS判断连通
  1. 状态压缩:一共才7段二极管,每段二极管都可以选或不选(全部不选不行),所以总共有27-1=127种方案,把1~127范围内的每个数转换成二进制,就对应到一种方案。
    例如,(23)10=(0010111)2,表示a,b,c,e选,其他二极管不选。
  2. 枚举每个方案,看是否符合要求。
  3. 构图:以二极管为顶点,二极管相邻则连边。
  4. DFS判断连通:对每一种方案,从该方案中任何一个选中的顶点出发进行DFS,跳过那些没有选中的顶点,DFS完毕,如果所有选中的顶点都遍历到,则说明是连通的,是一种符合题目要求的方案。

在这里插入图片描述

方法重点:DFS、构图。
特征:方案,计数
核心思路:枚举所有方案,对预设的方案,通过关联等条件搜索DFS能覆盖此方案中所有亮的二极管,那么此方案计入方案数。

代码

这段代码的目的是计算可以用七段数码管表示的、所有发光的二极管连成一片的不同字符的数量。下面是对代码的详细注释:

#include<bits/stdc++.h>
using namespace std;

// 定义七段数码管中各个段之间的连接关系
int g[7][7] = {
    0,1,0,0,0,1,0, // a段
    1,0,1,0,0,0,1, // b段
    0,1,0,1,0,0,1, // c段
    0,0,1,0,1,0,0, // d段
    0,0,0,1,0,1,1, // e段
    1,0,0,0,1,0,1, // f段
    0,1,1,0,1,1,0  // g段
};

// d数组用于标记当前方案中哪些段是亮的
int d[7];
// v数组用于标记在深度优先搜索中已经访问过的段
int v[7];

// 深度优先搜索函数,用于搜索所有与start相连的亮段
void dfs(int start) {
    for(int i = 0; i < 7; i++) {
        // 如果当前段i与start相连,且i段是亮的,且之前没有访问过i段
        if(g[start][i] == 1 && d[i] == 1 && v[i] == 0) {
            v[i] = 1; // 标记i段为已访问
            dfs(i); // 递归调用dfs,继续搜索从i段出发的相连亮段
        }
    }
}

int main() {
    int ans = 127; // 初始化答案为所有可能的组合数,即2^7 - 1(减1是因为至少有一个段是亮的)
    for(int i = 1; i <= 127; i++) { // 遍历所有可能的组合
        memset(d, 0, sizeof(d)); // 重置d数组为全0,表示所有段初始都是灭的
        memset(v, 0, sizeof(v)); // 重置v数组为全0,表示没有段被访问过
        int x = i, j = 0; // x为当前二进制数,j为当前位的索引
        // 将i的二进制表示分解为一个个位,并存储到d数组中
        while(x) {
            d[j++] = x % 2; // 存储当前位的亮灭状态
            x /= 2; // 移除已处理的位
        }
        // 找到第一个亮的段作为搜索的起点
        int start = 0;
        while(d[start] == 0) start++;
        v[start] = 1; // 标记起点为已访问
        dfs(start); // 从起点开始深度优先搜索
        // 检查是否所有的亮段都已经被访问过
        for(int j = 0; j < 7; j++) {
            if(d[j] == 1 && v[j] == 0) {
                ans--; // 如果有亮的段没有被访问过,说明当前方案不合法,答案减一
                break; // 跳出循环,继续下一个组合
            }
        }
    }
    cout << ans; // 输出最终的合法组合数
    return 0;
}

这段代码通过二进制的方式来表示每个字符的七段数码管的亮灭状态,然后通过深度优先搜索(DFS)来检查每个可能的组合是否满足题目中的条件(所有发光的二极管是连成一片的)。如果一个组合不满足条件,它会被排除,最终输出符合条件的字符数量。

方法二:bfs

这段代码的目的是使用广度优先搜索(BFS)来解决一个问题,具体来说,是计算在一个给定的图形(由七个点组成)中,有多少种方式可以使得所有点亮的点连成一片。这个问题可以通过检查每个点的连接性来解决。下面是对代码的详细注释:

#include<bits/stdc++.h>
using namespace std;

// ans用于记录连成一片的点亮点的数量
int ans;
// g[7][7]是一个二维数组,用于表示图形中点之间的连接关系
int g[7][7];
// vis[7]是一个数组,用于标记在BFS过程中已经访问过的点
int vis[7];
// flag[7]是一个数组,用于标记在检查过程中哪些点是亮的
int flag[7];

// BFS函数用于广度优先搜索,确定一个点是否连通其他亮的点
void bfs(int x){
    queue<int> que; // 定义一个队列用于BFS
    que.push(x); // 将起点x入队
    vis[x] = true; // 标记x为已访问
    while(!que.empty()){ // 当队列不为空时循环
        int u = que.front(); // 取出队列前端的点
        que.pop(); // 将该点从队列中移除
        for(int i = 0 ; i <= 6 ; i ++){ // 遍历所有与u相连的点
            if(g[u][i] && flag[i] && !vis[i]){ // 如果该点与u相连,且该点是亮的,且未被访问过
                vis[i] = true; // 标记为已访问
                que.push(i); // 将该点入队,继续BFS
            }
        }
    }
}

// check函数用于检查一个给定的二进制编码x是否表示一个连通的图形
bool check(int x){
    for(int i = 0 ; i <= 6 ; i ++) // 初始化flag和vis数组
        flag[i] = vis[i] = false;
    int cnt = 0; // 用于计数连通分量的数量
    for(int i = 6 ; ~i ; i --) // 遍历x的每一位
        if(x >> i & 1) flag[i] = true; // 如果某一位为1,则标记对应的点为亮的
    for(int i = 0 ; i <= 6 ; i ++){ // 再次遍历每个点
        if(flag[i] && !vis[i]){ // 如果点是亮的,但还未被访问
            bfs(i); // 执行BFS
            cnt ++ ; // 连通分量数量加一
        }
    }
    return cnt == 1; // 如果只有一个连通分量,返回true
}

int main()
{
    // 初始化g数组,表示图形中点之间的连接关系
    g[0][1] = g[0][5] = 1;
    g[1][0] = g[1][2] = g[1][6] = 1;
    g[2][1] = g[2][3] = g[2][6] = 1;
    g[3][2] = g[3][4] = 1;
    g[4][3] = g[4][5] = g[4][6] = 1;
    g[5][0] = g[5][4] = g[5][6] = 1;
    g[6][1] = g[6][2] = g[6][4] = g[6][5] = 1;
    // 遍历所有可能的二进制编码(0到127)
    for(int i = 0 ; i < (1 << 7) ; i ++){
        if(check(i)) { // 如果当前编码表示一个连通的图形
            ans ++ ; // 答案加一
        }
    }
    cout << ans << '\n'; // 输出答案
    return 0;
}

这段代码通过二进制编码来表示每个点的亮灭状态,然后使用BFS来检查每个点是否连通其他亮的点。check函数用于确定一个给定的编码是否表示一个连通的图形。如果是,那么答案ans就会增加。最后,程序输出所有可能的连通图形的数量。

标签:连通,int,二极管,蓝桥,start,发光,七段
From: https://blog.csdn.net/m0_73841621/article/details/137048274

相关文章

  • 2024 蓝桥打卡Day27
    D27ccfcsp代码练习材料整理Java中数组复制1.使用clone()方法2.使用System.arraycopy()方法四舍五入Arrays类进制转换十进制转其他进制其他进制转换为十进制保留小数位数使用String.format()使用DecimalFormat的format()方法使用String.formatArrayListHash......
  • P8736 [蓝桥杯 2020 国 B] 游园安排
    原题链接题解1.二分+dpcode#include<bits/stdc++.h>usingnamespacestd;stringname[1000005],dp[1000005],st[1000005];intmain(){strings;cin>>s;intcnt=0;for(inti=0;s[i];i++){if(isupper(s[i]))name[++cnt]=s[i];......
  • P8764 [蓝桥杯 2021 国 BC] 二进制问题
    原题链接题解1.如果数字为\(100110101\)那么答案为\(000000000\)~\(011111111\)中,k个1的组合数+\(100000000\)~\(100011111\)中k-1个1的组合数+...+\(1010101...\)(有k个1)中0个1的组合数,也就是1当遇见当遇见k个1后就可以退出了,最后判断数的1的个数够不够k,如果够......
  • 2024 蓝桥打卡Day26
    CCFCSP算法练习202212-1现值计算202212-2训练计划202209-1如此编码202209-2何以包邮?202206-1归一化处理202206-2寻宝!大冒险!202203-1未初始化警告202203-2出行计划202112-1序列查询202112-2序列查询新解......
  • 数字游戏(蓝桥杯历届真题)
    ##题目描述栋栋正在和同学们玩一个数字游戏。游戏的规则是这样的:栋栋和同学们一共n个人围坐在一圈。栋栋首先说出数字1。接下来,坐在栋栋左手边的同学要说下一个数字2。再下面的一个同学要从上一个同学说的数字往下数两个数说出来,也就是说4。下一个同学要往下数三个数,说7。依......
  • 备战蓝桥杯第三模块之二分模版+二分练题
    前言因本系列是为了蓝桥杯前几天快速过知识点所准备,所以有些部分会很简洁模版整数二分intMid(inta,intb){intl=1;intr=1e9+10;while(l<r){intmid=l+r>>2;if(a/mid<=b)//这儿一般情况下看需要用mid判断什么条件r=mid;elsel=......
  • 备战蓝桥杯第四模块之贪心
    前言本系列只是为了蓝桥杯前几天快速过一遍知识思路遇到贪心想想哪一种方案是最优解。需不需要排序区间选点题目数轴上有n个闭区间,取尽量少的点,使得每一个区间都至少有一个点思路1.优先选择那些终点较早的区间(右端点从小到大排序)2.逐一分析每一段区间是否包含点,如果......
  • NO12 蓝桥杯单片机之DS1302的使用
    1DS1302是什么DS1302由两块存储器组成,一个是日历时钟寄存器还有一个是31位的静态RAM存储器。而在蓝桥杯中常考的就是日历时钟寄存器,故这里只介绍日历时钟寄存器。简单来说,其就是一个“电子表”,他会自动的实时记录时间,而不需要像我们之前运用定时器做的时钟一样,要自己来设计......
  • 蓝桥杯嵌入式之AT24C02各种数据的读写
    一、1字节8为的读写u8a=10;u8temp;eeprom_write(0x00,a); temp=eeprom_read(0x00); sprintf(text,"  temp=%d ",temp);      LCD_DisplayStringLine(Line1,(u8*)text);      memset(text,'\0',strlen(text));二、对于uint16_t、int16_t......
  • 蓝桥杯 试题 基础练习 数列特征
    问题描述给出n个数,找出这n个数的最大值,最小值,和。输入格式第一行为整数n,表示数的个数。第二行有n个数,为给定的n个数,每个数的绝对值都小于10000。输出格式输出三行,每行一个整数。第一行表示这些数中的最大值,第二行表示这些数中的最小值,第三行表示这些数的和。样例输入5......