CCF 202009-3 点亮数字人生 python 满分

56 篇文章 4 订阅
这篇博客介绍了如何使用Python解决一个逻辑电路模拟问题,包括判断有向图环路的存在和按顺序执行逻辑功能。作者提到了两个主要难点,即环路检测和按顺序运行所有功能,并提供了相应的解决方案。代码示例中包含了邻接矩阵构建、拓扑排序和DFS判断环路的方法,以及模拟运算的完整流程。此外,还分享了关于深拷贝和输出处理的细节。
摘要由CSDN通过智能技术生成

题目叙述

问题描述:略

输入格式:略

输出格式:略

样例

样例输入1
1
3 5
XOR 2 I1 I2
XOR 2 O1 I3
AND 2 O1 I3
AND 2 I1 I2
OR 2 O3 O4
4
0 1 1
1 0 1
1 1 1
0 0 0
2 5 2
2 5 2
2 5 2
2 5 2


样例输出1
1 0
1 0
1 1
0 0


样例输入2
1
2 6
NOR 2 O4 I2
AND 2 O4 O6
XOR 2 O5 O1
NOT 1 O6
NAND 2 O2 O2
AND 2 I1 O3
2
0 0
1 0
3 2 3 4
6 1 2 3 4 5 6

样例输出2
LOOP

样例输入3
1
1 2
AND 2 I1 O2
NOT 1 O1
2
0
1
0 0
2 1 2

样例输出3
LOOP

样例输入4
1
2 4
AND 2 I1 I2
NAND 2 O1 O1
XOR 2 O2 O2
NOT 1 O2
2
0 1
1 1
0 0
2 1 2

样例输出4
1 0

样例输入5
1
3 9
AND 3 I1 I2 I3
OR 3 I1 I2 I3
AND 2 I1 I2
AND 2 I1 I3
AND 2 I2 I3
OR 2 O1 O7
AND 2 O2 O8
NOT 1 O9
OR 3 O3 O4 O5
8
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
2 6 9
2 6 9
2 6 9
2 6 9
2 6 9
2 6 9
2 6 9
2 6 9

样例输出5
0 0
1 0
1 0
0 1
1 0
0 1
0 1
1 1

样例输入6
1
3 8
NAND 2 O2 O3
NAND 2 I1 O4
NAND 2 I2 O4
NAND 2 I1 I2
NAND 2 O6 O7
NAND 2 O1 O8
NAND 2 I3 O8
NAND 2 O1 I3
8
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
1 5
1 5
1 5
1 5
1 5
1 5
1 5
1 5

样例输出6
0
1
1
0
1
0
0
1


满分证明

红色框框是我的,第一个是用C++写的(链接见参考)
在这里插入图片描述

解题思路

这题就是读起来太长了,不过理解了还好! 先说难点再说实现思路。

两个难点

第一,判断存在环路

该问题为判断有向图是否存在环路,要用到图的知识,用拓扑排序判断环或者DFS判断
构建邻接矩阵,然后使用上述两种中任意一种方式,有位大佬已经给出模块化公式,详情见参考博文链接。

第二,将全部FUNC(逻辑功能)按顺序读入运行

第一种思路
本来我想的是先将所有输入全为I(不需要运算)的器件读完,再将剩下的全部按O大小排序,依次读入。
想法很好,具体实现也实现了,但在测试参考博文1给出的样例时不能通过,才发现其中bug。进而转为采用第二种思路。
第二种思路
在每个器件后面加一个状态值,用while循环判定是否全部执行完。

具体实现思路

解决完上面两个难点,问题就简单很多了。

  1. 将所有具体逻辑功能进行封装成函数随时准备调用;
  2. 依据题意自行构建邻接矩阵(注意这里是有向图)函数模块;
  3. 判断有向图是否为环函数模块;
  4. 进行模拟运算函数模块;
  5. 主程序,按照题意的输入读入数据输出数据。

细节注意(在编写上述程序时有几个注意事项)

  1. 在具体逻辑功能函数中,虽然NOT只有一个参数,但为了和其他模块适配,也要写成传入数组的形式,方便管理;
  2. 在编写NAND和NOR函数时,注意调用NOT函数时,传入为数组;
  3. 一般在编写程序时,输出是在全部读入结束后进行。所以全部输出进行存储,最后一次输出;
  4. 在编写模拟运算函数时,涉及嵌套数组的复制(仅仅复制值,改变时原值不变),这里会涉及深度拷贝,不懂的可以查看参考博文3(讲的很详细);
  5. 在模拟运算函数时,整个模拟在while循环中进行,使用计数器判定是否跳出循环。先判断该运算函数有没有被执行过(每个函数的状态),再判断该运算函数能不能被执行(其运行的先决条件能否被满足)。第二个判断我是将所有输出赋值为-1,检测先决条件中有没有-1,再决定执不执行该运算函数;
  6. 在输出的时候也要注意LOOP的出现,作为特殊情况处理。

满分代码

import copy


def _NOT(ll):
    if not ll[0]:
        return 1
    else:
        return 0


def _AND(ll):
    st = ll[0]
    for i in range(1, len(ll)):
        st = st and ll[i]
    return st


def _OR(ll):
    st = ll[0]
    for i in range(1, len(ll)):
        st = st or ll[i]
    return st


def _XOR(ll):
    st = ll[0]
    for i in range(1, len(ll)):
        st = st ^ ll[i]
    return st


def _NAND(ll):
    return _NOT([_AND(ll)])


def _NOR(ll):
    return _NOT([_OR(ll)])


# 构建邻接矩阵
def buildmatrix(temfunc):
    mat = [[0] * len(temfunc) for _ in range(len(temfunc))]
    for i in range(len(temfunc)):
        for j in range(2, int(temfunc[i][1]) + 2):
            if temfunc[i][j][0] == "O":
                mat[int(temfunc[i][j][1:]) - 1][i] = 1
    return mat


# 判断是否存在环
def findcircle(G):
    node_set = set()
    r = len(G)
    have_in_zero = True
    while have_in_zero:
        have_in_zero = False
        for i in range(r):
            if i not in node_set and not any([row[i] for row in G]):
                node_set.add(i)
                G[i] = [0] * r
                have_in_zero = True
                break
    return False if len(node_set) == r else True


def light(S, M, N, ip, op, func):
    res = []
    for i in range(S):
        I = {}
        O = {}
        for j in range(1, M + 1):
            I[j] = ip[i][j - 1]
        for j in range(1, N + 1):
            O[j] = -1
        tem_func = copy.deepcopy(func)
        count = len(func)
        while count != 0:
            for p in range(len(func)):
                # 函数未被执行过
                if tem_func[p][-1]:
                    num = int(func[p][1])
                    te = ''
                    for k in range(num):
                        te += func[p][2 + k][0:1] + "[" + func[p][2 + k][1:] + "],"
                    tel = te[:-1]
                    if tel.find(",") != -1:
                        tep = list(eval(tel))
                    else:
                        tep = [eval(tel)]
                    if -1 not in tep:
                        O[p + 1] = eval("_" + func[p][0] + "(" + str(tep) + ")")
                        count -= 1
                        tem_func[p][-1] = False

        # 存储运算结果
        res.append(list(O[op[i][l]] for l in range(1, op[i][0] + 1)))

    return res


count = int(input())
fin = []
for _ in range(count):
    M, N = map(int, input().split())
    func = []
    ip = []
    op = []
    for _ in range(N):
        # 加一个状态值,判定有没有执行
        temp_func = list(map(str, input().split()))
        temp_func.append(True)
        func.append(temp_func)

    S = int(input())
    for _ in range(S):
        ip.append(list(map(int, input().split())))
    for _ in range(S):
        op.append(list(map(int, input().split())))
    if findcircle(buildmatrix(func)):
        fin.append("LOOP")
        continue
    fin.append(light(S, M, N, ip, op, func))
for i in range(len(fin)):
    for j in range(len(fin[i])):
        if fin[i] == "LOOP":
            print(fin[i])
            break
        for k in range(len(fin[i][j])):
            print(fin[i][j][k], end=" ")
        print()


感谢及参考博文

部分内容参考以下链接,这里表示感谢 Thanks♪(・ω・)ノ
参考博文1 点亮数字人生( 202009-3/CCF)———附带思路和完整代码(邻接表、邻接矩阵)
https://blog.csdn.net/qq_33375598/article/details/108914796
参考博文2 两种方式判断有向图是否有环-python实现
https://blog.csdn.net/songyunli1111/article/details/101559771
参考博文3 第 20 次 CSP认证-202009-Java-点亮数字人生(亮不起来T_T)(内附代码和若干测试用例)
https://blog.csdn.net/H_X_P_/article/details/108569908
参考博文4 Python的深浅拷贝
https://www.cnblogs.com/shiqizz/p/11514870.html

需者自取传送门(∩ᄑ_ᄑ)⊃━☆【CCF 2013-2021】本博主整理历年至少前两题 python 满分代码目录

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值