蓝桥杯:七段码

蓝桥杯:七段码

题目描述:

小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二
极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符
的表达时,要求所有发光的二极管是连成一片的。
例如:b 发光,其他二极管不发光可以用来表达一种字符。
例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上
一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。
例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光
的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?

答案:80
思路:
(觉得我啰嗦的可以直接看代码,有详细注释,还是挺好理解的)
大体思路并不难,分成两部分:一部分是遍历所有情况,第二部分是检查某种情况下是否连通。遍历比较简单,难点就在于如何检查连通。可以用并查集,不过我看别人弄的也挺复杂的,就没用并查集。(虽然我写的也挺复杂,,)
方便起见,把a,b,c,d,e,f这七段转换成0,1,2,3,4,5,6。像这样:
在这里插入图片描述

可以用字符串数组来保存连通的情况,比如str[1]=“026”。
用数组表示每个边的亮灭情况,索引代表边,1代表亮,0代表灭。

string str[7];
int arr[7] = { 0, 0, 0, 0, 0, 0, 0 };
void init()
{
	str[0] = "15";
	str[1] = "026";
	str[2] = "136";
	str[3] = "24";
	str[4] = "356";
	str[5] = "046";
	str[6] = "1245";
}

然后怎么判断连通呢?我最初(其实不是)想的是:遍历 arr,保存所有值为 1 的索引到 v 中,然后再遍历v中的每一个索引i,在其余值为1的索引所对应的 str 中找 i,如果其中有一个找到,就说明整个是连通的,如果都没有找到,就是不连通的。
这么想乍看没什么问题,但是运行结果是83。说明还有情况没有考虑到。我对着所有判断为连通的字符串一个一个找,终于发现了其他情况。就是0 1 亮,3 4灭。这种情况会被判断为连通。
这种情况的特征是:有多个边只被找到了一次。而正常连通的情况下,最多只会有两个边只被找到一次。按照这种思路修改代码,终于对了。
感想: 有我思考+写代码+调试的时间都够我一个一个数数5遍以上了,总共也就不超过128种,考试遇到这种填空题完全可以一个一个地数,不放心还能多数几遍,写代码很容易漏掉某些情况,反而容易错。。。。
完整代码:

#include <bits/stdc++.h>
using namespace std;
string str[7];                      //保存与第i段连通的边
int arr[7] = {0, 0, 0, 0, 0, 0, 0}; //表示每段的亮灭,1表示亮,0表示灭

void init() //初始化str
{
    str[0] = "15";
    str[1] = "026";
    str[2] = "136";
    str[3] = "24";
    str[4] = "356";
    str[5] = "046";
    str[6] = "1245";
}

bool check() //检查arr确定是否连通
{
    string s;                   //用来保存arr中值为1的所有索引
    for (int i = 0; i < 7; i++) //遍历arr
    {
        if (arr[i] == 1)
        {
            s.append(to_string(i));
        }
    }
    if (s.length() == 0)
        return false;
    if (s.length() == 1)
        return true;
    vector<int> v; //保存每个边被找到的次数
    for (int i = 0; i < s.length(); i++)
    {
        int num = 0; //用来保存第i个边被找到的次数
        for (int j = 0; j < s.length(); j++)
        {
            if (i == j)
                continue;
            if (str[s[j] - '0'].find(to_string(s[i] - '0')) != string::npos) //如果找到
            {
                num++;
            }
        }
        if (num == 0)
            return false;
        v.push_back(num);
    }
    int count = 0; //被找到次数为1的边的个数
    for (auto i : v)
    {
        if (i == 1)
            count++;
    }
    if (count > 2)
        return false;
    return true; 
}

string toString(int n) //十进制转成7位二进制字符串
{
    string s;
    for (int i = 0; i < 7; i++)
    {
        s = to_string(n & 1) + s;
        n = n >> 1;
    }
    return s;
}

int fun()
{
    init();
    int ans = 0;
    for (int i = 0; i < 128; i++) //通过二进制从0加到128遍历所有情况
    {
        string s = toString(i);
        for (int j = 0; j < 7; j++)
        {
            arr[j] = s[j] - '0';
        }
        if (check())
        {
            ++ans;
        }
    }
    return ans;
}

int main()
{
    cout << fun() << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值