蓝桥杯真题七段码

题目:

七段码对应的a、b、c、d、e、f、g分别用数字0,1,2,3,4,5,6表示

一、DFS+check函数

这里与普通的dfs并不相同,因为这里的dfs不要求一定要到达叶子节点,但是dfs方法走了很多多余的路太笨了,这是我最开始的想法。

代码如下:

## a存储七段数码管的邻接矩阵
a = [[1,1,0,0,0,1,0],
     [1,1,1,0,0,0,1],
     [0,1,1,1,0,0,1],
     [0,0,1,1,1,0,0],
     [0,0,0,1,1,1,1],
     [1,0,0,0,1,1,1],
     [0,1,1,0,1,1,1]]
## check函数检查 i是否可以加入light中
def check(light,i):
    ## 重复加入
    if str(i) in light:
        return False
    ## light为空怎么加入都对
    if len(light) == 0:
        return True
    ## 有一个相连即可加入light
    for j in light:
        if a[i][int(j)] == 1:
            return True
    return False
light = []
## ans 设置成set是为了不重复解,但是感觉dfs还是不太适用于这一题
ans = set()
def dfs(k):
    if k > 7:
        ## 这里直接返回了,正常的其他dfs到达了叶子节点需要做记录,这里由于不要求到叶子节点直接返回即可
        return True
    for i in range(7):
        if check(light,i):
            light.append(str(i))
            ## 这里是参考别人的,set里面加list会报错,字符串更加方便
            ans.add("".join(sorted(light)))
            dfs(k+1)
            light.pop()
        else:
            continue
dfs(0)
print(f"{len(ans)}")
print(ans)

上面总觉得有点杀鸡用牛刀,而且在存储解的时候会有点麻烦,后面看了一下别人的解法有了下面的思路。

二、二进制表示七段数码管+并查集

这里曾经走过一条弯路,一开始想通过检查每一个在内的节点是否至少有一个节点与之相连来判断是否连通,最终的答案是83,比正确答案多三个排查后发现,这种方法有缺陷,那就是忽略了节点与节点之间互相“包庇”的情况比如:1245,0134,0523。这里真的太鸡儿搞人了,最最开始还陷入内一个弯路:认为亮a个的数量和7-a个的数量是一样的,但是其实只有少数a成立,反例为:165和0234.

## 弯路一 忽略了节点之间互相“包庇”的情况
def check(light):
    light_list = []
    for i in range(len(light)):
        if light[i] ==  "1":
            light_list.append(i)
    if len(light_list) == 1:
        return True
    temp = 0
    for i in light_list:
        for j in light_list:
            if a[i][j] == 1:
                temp += 1
        if temp <=  1:
            return False
        temp = 0
    return True

这里先写一下最原始的并查集的代码(如果不了解并查集就先看并查集吧):

## 这里fa的长度应该与所有元素点的个数相同
fa = [i for i in range(7)]
def ini():
    fa = [i for i in range(7)]
def find(x):
    if fa[x] == x:
        return x
    else:
        ## 这里使用了距离缩减
        fa[x] = find(fa[x])
        return fa[x]
def union(a,b):
    a_fa = find(a)
    b_fa = find(b)
    fa[a_fa] = b_fa

 最终思路二的代码:

con = {0:[1,5],
       1:[0,2,6],
       2:[1,6,3],
       3:[2,4],
       4:[3,5,6],
       5:[0,6],
       6:[1,2,4,5]
    }


def check(light):
    light_list = []
    for i in range(len(light)):
        if light[i] == "1":
            light_list.append(i)
    if len(light_list) ==  1:
        return True
    fa = [i for i in range(7)]
    def find(x):
        if fa[x] == x:
            return x
        else:
            fa[x] = find(fa[x])
            return fa[x]
    def union(a,b):
        a_fa = find(a)
        b_fa = find(b)
        fa[a_fa] = b_fa
    for key in light_list:
        for i in con[key]:
            if i in light_list:
                union(key,i)
    count = 0
    for i in light_list:
        if find(light_list[0]) != find(i):
            return False
    return True
ans = 0
for i in range(1,128):
    temp = f"{i:>07b}"[::-1]
    if check(temp):
        ans +=  1
print(f"{ans}")


唯一要注意的点是:在check函数中union(a,b)除了判断a是否在light_list中,还需要判断b是否也在light_list中,否则会有“偷渡”的情况产生(通过中间没有亮的点连通了)。

这次的收获:并查集+二进制表示

2023.01.02更新:

三、itertools+并查集

import itertools
a = {0:[1,5],
     1:[0,2,6],
     2:[1,3,6],
     3:[2,4],
     4:[3,5,6],
     5:[0,4,6],
     6:[1,2,4,5]}
def lian(n):
    fa = [_ for _ in range(7)]
    def find(a):
        if fa[a] == a:
            return a
        else:
            fa[a] = find(fa[a])
            return fa[a]
    def union(a,b):
        a_fa = find(a)
        b_fa = find(b)
        fa[a_fa] = b_fa
    if len(n) == 1:
        return True
    for i in n:
        for j in a[int(i)]:
            if str(j) in n:
                union(int(i),j)
    for i in n:
        if find(int(n[0])) != find(int(i)):
            return False
    return True
ans = 0
for length in range(1,8):
    for i in itertools.combinations("0123456",r = length):
        if lian("".join(i)):
            ans += 1
print(ans)

收获:itertools

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值