CCF 202009-3 点亮数字人生 python 满分
题目叙述问题描述:略输入格式:略输出格式:略样例
满分证明解题思路两个难点第一,判断存在环路第二,将全部FUNC(逻辑功能)按顺序读入运行
具体实现思路
满分代码感谢及参考博文
题目叙述
问题描述:略
输入格式:略
输出格式:略
样例
样例输入
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循环判定是否全部执行完。
具体实现思路
解决完上面两个难点,问题就简单很多了。
将所有具体逻辑功能进行封装成函数随时准备调用;依据题意自行构建邻接矩阵(注意这里是有向图)函数模块;判断有向图是否为环函数模块;进行模拟运算函数模块;主程序,按照题意的输入读入数据输出数据。
细节注意(在编写上述程序时有几个注意事项)
在具体逻辑功能函数中,虽然NOT只有一个参数,但为了和其他模块适配,也要写成传入数组的形式,方便管理;在编写NAND和NOR函数时,注意调用NOT函数时,传入为数组;一般在编写程序时,输出是在全部读入结束后进行。所以全部输出进行存储,最后一次输出;在编写模拟运算函数时,涉及嵌套数组的复制(仅仅复制值,改变时原值不变),这里会涉及深度拷贝,不懂的可以查看参考博文3(讲的很详细);在模拟运算函数时,整个模拟在while循环中进行,使用计数器判定是否跳出循环。先判断该运算函数有没有被执行过(每个函数的状态),再判断该运算函数能不能被执行(其运行的先决条件能否被满足)。第二个判断我是将所有输出赋值为-1,检测先决条件中有没有-1,再决定执不执行该运算函数;在输出的时候也要注意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