📜  门|门模拟 2017 |第 35 题(1)

📅  最后修改于: 2023-12-03 14:58:37.649000             🧑  作者: Mango

门|门模拟 2017 |第 35 题

本题是一个电路模拟问题,你需要实现一个简易的电路模拟器,支持门电路的构建和计算。

问题描述

题目给定一个电路结构以及各个门的类型和输入输出关系,需要计算电路的输出。电路由多个门和导线组成,每个门可以有多个输入和一个输出,每个导线连接两个门或一个门和一个输入节点或输出节点。题目中规定输入节点的编号为负数,输出节点的编号为正数。

在计算电路输出的过程中,需要遍历电路中所有的门并计算它们的输出。具体计算方式如下:

  • 输入节点的值已知,将其值传递给与其相连的门,根据门的类型计算并得出输出;
  • 导线的值与输出相关联的门的输入相连;
  • 门的输入已知时,计算门的输出;
  • 计算输出节点的值。

对于某些电路,可能存在循环依赖关系。例如,两个门 A 和 B 互相输入,这种情况下需要处理成同时计算两个门的输出,直至收敛。

输入格式

输入包含若干行,每行代表一个门或者导线的描述。

门的描述格式为:

gate_id gate_type input_1 input_2 ... input_n
  • gate_id :门的编号,为一个整数;

  • gate_type :门的类型,为以下值之一:

    • 0 :AND 门,计算所有输入门的逻辑与,并将结果输出;
    • 1 :OR 门,计算所有输入门的逻辑或,并将结果输出;
    • 2 :XOR 门,计算所有输入门的逻辑异或,并将结果输出;
    • 3 :NOT 门,将输入门的逆取值作为输出。
  • input_1 到 input_n :门的输入,为负整数或前面已定义的门的编号。

导线的描述格式为:

0 input_gate_id output_gate_id
  • input_gate_id :导线输入的门的编号;
  • output_gate_id :导线输出的门的编号或输出节点的编号。
输出格式

输出包含一个整数,代表整个电路的输出值。

样例输入1
1 3 -2
2 3 -3
3 2 1 2
4 3 -1 3
5 3 3 4
0 5 1
样例输出1

1

样例解释1

上述电路可以用如下图示表示:

        1
        ↓
        3 - 5 -|→4
        ↓
        2
  • 门 1 取输入节点 -2 的逆取值作为输出 0,门 3 取输入节点 -3 的逆取值作为输出 1;
  • 门 5 计算门 3 和门 4 的逻辑或,输出 1;
  • 门 4 计算门 1 和门 5 的逻辑与,输出 1;
  • 最终输出 1。
样例输入2
1 3 -2
2 3 3
3 0 1 4
4 3 -1 3
0 2 5
5 1 -3
样例输出2

0

样例解释2

上述电路可以用如下图示表示:

          5
          ↓
        2 - 3 - 4 -|→输出
      ↗ ↑
  1 -|-↓
      ↓
     -3
  • 门 1 取输入节点 -2 的逆取值作为输出 0;
  • 门 4 计算门 1 和门 3 的逻辑与,输出 0;
  • 门 3 计算其输入门门 1 和门 4 的逻辑与,改变其输出值;
  • 门 2 计算其多个输入门门 3 的输出,输出 0;
  • 输出节点 5 计算门 2 的输出,输出 0;
  • 最终输出 0。
代码实现
class Wire:
    def __init__(self, gate):
        self.gate = gate
        self.value = None


class Gate:
    def __init__(self, gtype, inputs, outputs):
        self.gtype = gtype
        self.inputs = inputs
        self.outputs = outputs
        self.value = None
        self.wires_in = [Wire(self) for _ in range(len(inputs))]
        self.wires_out = [Wire(self) for _ in range(len(outputs))]

    # Set value if all inputs are available
    def calculate(self):
        if None in [w.value for w in self.wires_in]:
            return
        if self.gtype == 0:
            self.value = all(w.value for w in self.wires_in)
        elif self.gtype == 1:
            self.value = any(w.value for w in self.wires_in)
        elif self.gtype == 2:
            self.value = sum(w.value for w in self.wires_in) == 1
        elif self.gtype == 3:
            self.value = not self.wires_in[0].value

    # Propagate value to output wires and gates
    def propagate(self):
        for wire in self.wires_out:
            if wire.gate in processed_gates:
                continue  # Stop recursion if gate has already been processed
            wire.value = self.value
            processed_wires.append(wire)
            wire.gate.calculate()
            processed_gates.append(wire.gate)
            wire.gate.propagate()


inputs = {}
outputs = {}
wires = {}
gates = []

# Parse input
for i in range(int(input())):
    words = input().split()
    gate_id = int(words[0])
    inputs[gate_id] = True
    gate_type = int(words[1])
    inputs_gates = [int(w) for w in words[2:]]
    outputs_gates = [inputs_gates.pop()]
    for input_gate_id in inputs_gates:
        if input_gate_id not in wires:
            wires[input_gate_id] = []
        wires[input_gate_id].append(gate_id)
    for output_gate_id in outputs_gates:
        if output_gate_id not in wires:
            wires[output_gate_id] = []
        wires[gate_id] = [output_gate_id]

        if output_gate_id in inputs:
            outputs[gate_id] = True

    gates.append(Gate(gate_type, inputs_gates, outputs_gates))

# Calculate output(s)
processed_wires = []
processed_gates = []
for input_gate_id in inputs:
    if input_gate_id not in wires:
        continue
    for output_gate_id in wires[input_gate_id]:
        if output_gate_id in inputs:
            continue
        outputs[output_gate_id] = True
        wires[input_gate_id].remove(output_gate_id)
        gates.append(Gate(None, [input_gate_id], [output_gate_id]))

for gate in gates:
    gate.calculate()
    processed_gates.append(gate)
    for wire in gate.wires_out:
        wire.value = gate.value
        processed_wires.append(wire)

while True:
    new_wires = []
    for wire in processed_wires:
        for connected_gate in wires.get(wire.gate.outputs[0], []):
            new_wire = Wire(connected_gate)
            new_wire.value = wire.value
            processed_gates.append(connected_gate)
            connected_gate.wires_in[connected_gate.inputs.index(wire.gate.outputs[0])] = new_wire
            new_wires.append(new_wire)
    if not new_wires:
        break
    processed_wires = new_wires

processed_wires = []
processed_gates = []
for gate in gates:
    if gate.gtype is None:
        continue  # Skip input-only gates
    if gate in processed_gates:
        continue  # Skip reprocessing gates
    processed_gates.append(gate)
    gate.propagate()

print(int(any(gate.value for gate in gates if gate.gtype is None and gate.outputs[0] in outputs)))

代码简介:

类 Wire 代表一个导线,其属性 gate 表示连接到的门,value 表示当前导线上的值。类 Gate 代表一个门,其中 gtype、inputs 和 outputs 分别为门的类型、输入和对应的输出门节点或输出节点编号。Gate 实例的 wires_in 和 wires_out 为输入和输出导线组成的列表,其中每个元素为 Wire 实例。calculate() 和 propagate() 分别用于计算门的输出和将输出传递到下一级门。

程序从标准输入中读取输入数据,并尝试构建出电路结构。实现过程中,将所有输入门(编号为负数)和输出节点(编号为正数)记录到 inputs 和 outputs 字典中,依次读取每个门的描述,先处理导线,再处理输入和输出门,最后根据输入门的值计算电路的输出。在计算时,如果门的输入尚未全部就绪,将不进行计算,直至计算完全可行。为处理循环依赖,采用了递归向下传值的方式,在计算出所有正在使用中的门的输出后,对输出值已知的门向下传值,直至传递到输出节点或未连通的门。

最后输出输出节点的值或者逻辑或的结果即可。