蓝桥杯2020年真题---七段码--简单易懂

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

上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二

极管,分别标记为 a, b, c, d, e, f, g。

小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符

的表达时,要求所有发光的二极管是连成一片的。

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

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

这种方案与上一行的方案可以用来表示不同的字符,尽管看上去比较相似。

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

例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光

的二极管没有连成一片。

思路:

7个灯管共有127种情况。用二进制表示即从0000000到1111111。

每一位二进制分别表示每个灯管的亮灭情况。(0表示灭,1表示亮)

将这127种二进制数连通图相结合进行判断得出符合要求的灯管并计数。

127种二进制数用来判断灯的亮灭。

连通图在上一个条件下用来判断亮的灯是否连通。

先上代码,后面根据代码进行讲解
//全局变量
static int count=0;//计数
    static int[][] m= {//连通矩阵
            {0,1,0,0,0,1,0},
            {1,0,1,0,0,0,1},
            {0,1,0,1,0,0,1},
            {0,0,1,0,1,0,0},
            {0,0,0,1,0,1,1},
            {1,0,0,0,1,0,1},
            {0,1,1,0,1,1,0}
    };
    static char[] a;//存储127种情况的二进制字符数组
    static boolean flag;//用来标记符合要求的情况
    public static void main(String[] args) {

        for (int j = 1; j < 128; j++) {//对127种情况进行循环
            // 获取127种情况的二进制,并取反(a[0]表示灯管0,以此类推a[6]表示灯管6)与连通图首位对应
            StringBuffer s=new StringBuffer(Integer.toBinaryString(j)).reverse();
            a=s.toString().toCharArray();//将二进制数转为字符数组
            int[] f={1,1,1,1,1,1,1};//将每个灯管标记为“未遍历”
            flag=true;//初始化标记
            for(int i=0;i<a.length;i++){//循环二进制找到第一个亮灯的
                f[i]=0;//未亮灯且标记为被遍历过
                if(a[i]=='1')
                {
                    dfs(f,i);//以第一个亮灯的灯管为开始遍历所有灯管
                    break;
                }
            }
            if(flag==false)count++;//符合要求则计数
        }
        System.out.println(count);//结果输出
    }
    public static void dfs(int[] f,int k){//k表示亮灯的灯管序号
        f[k]=0;//标记为遍历过
        for(int i=0;i<a.length;i++){在连通图中第k行寻找连通且亮灯的灯管进行遍历
            if(m[k][i]==1&&a[i]=='1'){//连通且亮着
                if(f[i]==1)//未被遍历过
                    dfs(f,i);//寻找下一个
            }
        }
        for(int i=0;i<a.length;i++){//存在未被连通的,即无法连通的
            if(f[i]==1&&a[i]!='0')//存在亮灯但不连通的灯管
                return;//返回上一层
        }
        flag=false;//每个灯管被遍历且亮灯的灯管是连通的
        return;//返回上一层
    }

步骤:

  1. 对127种情况进行二进制表示

  1. 将二进制数反转,使其下标与数码管序号一一对应

  1. 将二进制数每一位标记为未被遍历。f={1,1,1,1,1,1,1}1表示未被遍历,0表示已遍历

  1. 找到二进制中第一个'1'(第一个亮灯的灯管)对其进行遍历,并将其标记为已遍历

  1. 通过dfs()方法在连通图第k行寻找连通且亮灯的灯管,对其再进行遍历,并将其标记为已遍历过(f[k]=0)

  1. 直到遍历完二进制每一位数

  1. 循环判断数组f是否存在未遍历或遍历了但灯是灭的情况。(是否存在f[i]==1&&a[i]!='0')如果存在则表示不连通,不存在表示连通,并标记flag=false再递归返回上一层。

  1. 如果7个灯管都遍历完了且均符合要求,则计数+1

  1. 循环下一种情况(循环步骤1)

举例:

1、a=101010,a'=010101(表示1、3、5号灯管灯亮,其余灯灭)

找到第一个亮灯灯管下标为1。调用dfs(f,1)。(此时f={0,0,1,1,1,1,1})

在连通图第k行(k=1)寻找可连通的灯管

按顺序发现与1号灯管连通的有0号灯管,由于f[0]=0已被遍历过,继续寻找。

2号灯管也连通,判断a[2]='0'灯是灭的,继续寻找。

由于a的长度为6,a[6]='0'(第7个灯管是灭的),不用考虑,直接跳过。

由于循环7个灯管后均未找到与第一个灯管相连且亮灯的灯管,于是进入下一个循环。

对每个二进制标记进行判断(f={0,0,1,1,1,1,1})

发现在查询过连通情况后仍然有亮灯的未被遍历,表明亮灯的灯管不连通,则不计数直接退出函数。

进入下一种情况继续判断。

2、a=1111000,a'=0001111(表示3、4、5、6号灯管是亮的)

找到第一个亮灯的灯管序号为3。调用dfs(f,3)。(此时f={0,0,0,0,1,1,1})

在连通图第k行(k=3)寻找可连通的灯管

按顺序发现2号管可连通,由于f[2]=0,表示已被遍历过。继续寻找

发现4号灯管也可连通,同时f[4]=1表示未遍历,a[4]='1'表示亮灯,则调用dfs(4),同时将4号灯管标记为已遍历过f[4]=0

查找连通图第4行,发现3号灯管可连通,由于f[3]=0已被遍历过,继续寻找

发现5号灯管也可连通,f[5]=1表示未遍历,a[5]='1'表示灯亮,则调用dfs(5),同时将5号灯管标记为已遍历过f[5]=0

查找连通图第5行,发现0号灯管可连通,由于f[0]=0已被遍历过,继续寻找

发现4号灯管可连通,由于f[4]=0已被遍历过,继续寻找

发现6号灯管也可连通,f[6]=1表示未遍历,a[6]='1'表示灯亮,则调用dfs(6),同时将6号灯管标记为已遍历过f[6]=0

遍历连通图第6行,由于f[0..6]=0表示所有灯管都被遍历过,直接递归返回上一层即dfs(5)执行结束后的位置。

循环判断数组f发现都已遍历,则flag=false并递归返回dfs(4)的结束位置。

继续循环第4行发现6号灯管也可连通,由于f[6]=0表示已遍历,则退出循环。

循环判断数组f发现都已遍历,则flag=false并递归返回dfs(3)的结束位置。

继续循环第3行,发现5,6号灯管与3号灯管不连通,退出循环。

循环判断数组f发现都已遍历,则flag=false并递归返回。由于dfs(3)是第一个递归函数,递归返回就是直接结束主函数中的dfs()方法。

发现flag=false,对count+1

进入下一种情况继续判断。

猜你喜欢

转载自blog.csdn.net/weixin_61936651/article/details/129765081