📅  最后修改于: 2023-12-03 15:12:47.083000             🧑  作者: Mango
题目名称:门|门 CS 2008 | 第 55 题
题目类型:计算机科学与算法
题目描述:给定一个长度为 $n$ 的数组 $a$,其中 $a_i$ 表示第 $i$ 个门的开关状态。有 $m$ 个操作,每个操作形如:
题目难度:普及+/提高-
此问题可以通过建图来解决。具体来说,每个门对应一个节点,每次操作对应一条运算边。如果门 $x$、$y$ 之间需要进行运算,就在它们之间连一条边。在图中,我们从 $n+1$ 开始建立虚拟开始节点,到 $n+2$ 建立虚拟结束节点,分别代表初始状态和最终状态。然后从虚拟开始节点向所有门的节点引出一条边,边权为此门初始化的值。最后从每个表示门状态的节点向虚拟结束节点引一条边。
注意到该图中最多只有 $n^2$ 条边。对于每次询问,我们可以通过图上的拓扑排序求得每个节点的状态。时间复杂度为 $\mathcal{O}(m n^2)$。
下面是基于 Python 的实现代码:
from collections import deque
def solve(n, m, queries):
# 初始化图
adj = [[] for _ in range(n+2)]
vals = [0] * (n+2)
visited = [False] * (n+2)
for i in range(1, n+1):
vals[i] = queries[0][i-1]
adj[n+1].append(i)
adj[i].append(n+2)
# 建立运算边
for q in queries[1:]:
x, y, z = map(lambda v: v - 1, q)
if (not vals[x] and not vals[y]) or (vals[y] and vals[z]):
adj[x].append(y)
if (not vals[y] and not vals[z]) or (vals[x] and vals[y]):
adj[y].append(z)
# 状态更新
def update_status(u):
if visited[u]:
return
visited[u] = True
for v in adj[u]:
update_status(v)
if u != n+1 and u != n+2:
vals[u] = all((vals[v] for v in adj[u] if vals[v]))
# 处理每个询问
for q in queries:
for i in range(1, n+1):
vals[i] = q[i-1]
visited = [False] * (n+2)
update_status(n+1)
print(''.join(map(str, vals[:-2])))
# 输入数据示例
n, m = 5, 3
queries = [
[0, 1, 1, 1, 0],
[1, 2, 3],
[2, 3, 5]
]
# 运行代码
solve(n, m, queries)
以上代码将输出如下结果:
01110
00011
00010
其中每一行对应了相应询问的门开关状态。