📜  门| GATE-CS-2016(套装2)|问题 14(1)

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

门 | GATE-CS-2016(套装2)|问题 14

本题考察了计算机科学中“门”的概念,是一道典型的逻辑电路设计问题。

问题描述

现在有一个逻辑电路,其中有 $n$ 个输入线和 $m$ 个输出线,同时电路中包含以下三种门:

  1. NOT 门:该门只有一个输入线和一个输出线,其输出端口与输入端口相反,即当输入端口为 $0$ 时,输出端口为 $1$,反之亦然。
  2. AND 门:该门有两个输入线和一个输出线,只有当两个输入均为 $1$ 时,输出才为 $1$,否则输出为 $0$。
  3. OR 门:该门有两个输入线和一个输出线,只要两个输入中有一个为 $1$,输出就为 $1$,否则输出为 $0$。

现在,你需要使用这三种门来设计出一个新的逻辑电路,用来实现 $f(x_1, x_2, ..., x_n) = g(y_1, y_2, ..., y_m)$,其中:

  1. 输入端口为 $x_1, x_2, ..., x_n$,输出端口为 $y_1, y_2, ..., y_m$;
  2. $g(y_1, y_2, ..., y_m)$ 是一个给定的布尔函数,它只涉及变量 $y_1, y_2, ..., y_m$(但不一定是所有变量),且其中至多包含 $k$ 个项,每个项都是一个 $y_i$ 或 $y_i$ 的否定 $y_i'$;
  3. 对于 $i = 1, 2, ..., n$,$x_i$ 可以为 $y_j$ 或者 $y_j'$ 的形式。

注意,你需要使用最少的门来实现这个电路,并且输入中 $x_i$ 可以重用。对于每个测试用例,你需要输出用来实现逻辑电路的最小门数量以及对应的电路图。假设输入是 $x_1 = y_1'$,则需要在电路图中表示出这个反转结构,并且该结构不计入门数量里面。

解题思路

在这个问题中,我们需要将给定的布尔函数 $g(y_1, y_2, ..., y_m)$ 转换为逻辑电路实现的形式。又因为我们只能使用三种门:NOT、AND、OR,所以我们需要将给定的布尔函数经过一系列转换后,转换为上述三种门的组合形式,才能完成电路的设计。

具体而言,我们可以通过以下步骤来设计电路:

  1. 将 $g(y_1, y_2, ..., y_m)$ 转换为其标准形式,即将其中所有项变为若干个 AND 门的输入,并在所有这些 AND 门的输出之间使用 OR 门连接。例如对于 $g(y_1, y_2, y_4) = (y_1' \land y_2 \land y_4) \lor (y_1 \land y_2' \land y_4)$,其标准形式为:

    $$ g(y_1, y_2, y_4) = (y_1' \land y_2 \land y_4) \lor (y_1 \land y_2' \land y_4) = (y_1' \land y_2 \land y_4) \lor (y_1 \land y_2' \land y_4 \land 1) \lor (y_1 \land y_2' \land y_4' \land 0) $$

    其中,$1$ 表示一个常量输入,始终为 $1$,$0$ 表示一个常量输入,始终为 $0$。

  2. 将标准形式中的每个 AND 门和 OR 门分别使用 NOT 门转换为 NAND 门和 NOR 门,并且每个输出都使用 NOT 门转换为其反向输出(若没有 NOT 门则加入,若已经有 NOT 门则不需再加入)。

    例如,对于上述标准形式,经过该转换后得到

    $$ \begin{aligned} g(y_1, y_2, y_4) &= \text{NOT}(\text{NAND}(\text{NOT}(y_1'), \text{NAND}(y_2, y_4'))) \lor \text{NOT}(\text{NAND}(\text{NOT}(y_1), \text{NAND}(y_2', y_4))) \ &= \text{NOR}(\text{NOR}(\text{NOT}(y_1)), \text{NOR}(y_2, y_4')) \land \text{NOR}(\text{NOR}(y_1', \text{NOT}(y_2')), \text{NOR}(y_4, 1)) \end{aligned} $$

  3. 根据题意,对于每个 $x_i$,将其实现为 $y_j$ 或 $y_j'$ 的形式,也就是说,它要么直接连接到一个 $y_j$ 或 $y_j'$ 的输入端口上,要么先通过 NOT 门反转后再连接。注意,如果存在 $x_i = y_j'$ 的形式,则需要在对应的输入端口上反转信号,这可以通过添加一个额外的 NOT 门实现。

  4. 最后,将所有的 NAND、NOR、NOT、AND、OR 门用向量的形式输出,即可完成本题。

代码实现
def convert_to_nand(x):
    # 将布尔表达式转为 Nand 表达式
    x = x.replace('(', '').replace(')', '')  # 去除括号
    x = x.replace('not', 'nand(1,')  # not -> nand with 1
    x = x.replace('and', 'nand(')  # and -> nand
    x = x.replace('or', 'nand(nand(')  # or -> nand(nand)
    x = x.replace(',', ', ')  # 在逗号后添加空格
    x = x.replace('y', 'x')  # 将 y 替换为 x(便于后续实现)
    x += ' '  # 加入空格是为了避免最后一个括号被误删除
    x = list(x)
    res = []
    for i in range(len(x)):
        if x[i] == ')' and (i == len(x) - 1 or x[i + 1] != ' '):
            res.append(x[i])  # 保留括号(避免错误删除)
        elif x[i] == ')':
            while res and res[-1] != '(':
                res.pop()  # 删掉最后一个括号中的多余空格
            res.pop()  # 删掉空格或逗号
            while res and res[-1] != 'n' and res[-1] != '(':
                res.pop()  # 删掉所有输出变量之前的多余空格和 n
            if res and res[-1] == 'n':
                res.pop()  # 删掉最后一个 n(避免出现 nnand、nnor 等)
            res.append(' ')  # 添加空格
        else:
            res.append(x[i])

    return ''.join(res)

def convert_to_nor(x):
    # 将布尔表达式转为 Nor 表达式
    return x.replace('nand', 'nor').replace('1,', '').replace('nand', '1,')

def and_gate(x, y):
    # AND 门
    return f'(and {x} {y})'

def or_gate(x, y):
    # OR 门
    return f'(or {x} {y})'

def not_gate(x):
    # NOT 门
    return f'(not {x})'

def nand_gate(x, y):
    # NAND 门
    return f'(nand {x} {y})'

def nor_gate(x, y):
    # NOR 门
    return f'(nor {x} {y})'

def bool_func_to_circuit(n, m, k, g):
    # 实现布尔函数
    circ = []
    # 将布尔函数转为 NAND 表达式
    f = convert_to_nand(g)
    # 将 NAND 表达式转为 NOR 表达式
    f = convert_to_nor(f)
    # 将 NOR 表达式转为电路图
    tmp = []
    for c in f:
        # 变量
        if c >= 'x' and c <= chr(ord('x') + m - 1):
            tmp.append(c)
        # 反向变量
        elif c >= 'x' and c <= chr(ord('x') + m - 1) + 1:
            tmp.append(not_gate(c))
        # 逗号或空格
        elif c == ',' or c == ' ':
            pass
        # OR 连接
        elif c == 'r':
            while len(tmp) > 1:
                t1 = tmp.pop()
                t2 = tmp.pop()
                tmp.append(or_gate(t1, t2))
        # NAND 连接
        else:
            while len(tmp) > 1:
                t1 = tmp.pop()
                t2 = tmp.pop()
                tmp.append(nand_gate(t1, t2))
    # 输出最终的电路图
    circ += tmp

    return len(circ), '\n'.join(circ)
完整代码
def convert_to_nand(x):
    # 将布尔表达式转为 Nand 表达式
    x = x.replace('(', '').replace(')', '')  # 去除括号
    x = x.replace('not', 'nand(1,')  # not -> nand with 1
    x = x.replace('and', 'nand(')  # and -> nand
    x = x.replace('or', 'nand(nand(')  # or -> nand(nand)
    x = x.replace(',', ', ')  # 在逗号后添加空格
    x = x.replace('y', 'x')  # 将 y 替换为 x(便于后续实现)
    x += ' '  # 加入空格是为了避免最后一个括号被误删除
    x = list(x)
    res = []
    for i in range(len(x)):
        if x[i] == ')' and (i == len(x) - 1 or x[i + 1] != ' '):
            res.append(x[i])  # 保留括号(避免错误删除)
        elif x[i] == ')':
            while res and res[-1] != '(':
                res.pop()  # 删掉最后一个括号中的多余空格
            res.pop()  # 删掉空格或逗号
            while res and res[-1] != 'n' and res[-1] != '(':
                res.pop()  # 删掉所有输出变量之前的多余空格和 n
            if res and res[-1] == 'n':
                res.pop()  # 删掉最后一个 n(避免出现 nnand、nnor 等)
            res.append(' ')  # 添加空格
        else:
            res.append(x[i])

    return ''.join(res)

def convert_to_nor(x):
    # 将布尔表达式转为 Nor 表达式
    return x.replace('nand', 'nor').replace('1,', '').replace('nand', '1,')

def and_gate(x, y):
    # AND 门
    return f'(and {x} {y})'

def or_gate(x, y):
    # OR 门
    return f'(or {x} {y})'

def not_gate(x):
    # NOT 门
    return f'(not {x})'

def nand_gate(x, y):
    # NAND 门
    return f'(nand {x} {y})'

def nor_gate(x, y):
    # NOR 门
    return f'(nor {x} {y})'

def bool_func_to_circuit(n, m, k, g):
    # 实现布尔函数
    circ = []
    # 将布尔函数转为 NAND 表达式
    f = convert_to_nand(g)
    # 将 NAND 表达式转为 NOR 表达式
    f = convert_to_nor(f)
    # 将 NOR 表达式转为电路图
    tmp = []
    for c in f:
        # 变量
        if c >= 'x' and c <= chr(ord('x') + m - 1):
            tmp.append(c)
        # 反向变量
        elif c >= 'x' and c <= chr(ord('x') + m - 1) + 1:
            tmp.append(not_gate(c))
        # 逗号或空格
        elif c == ',' or c == ' ':
            pass
        # OR 连接
        elif c == 'r':
            while len(tmp) > 1:
                t1 = tmp.pop()
                t2 = tmp.pop()
                tmp.append(or_gate(t1, t2))
        # NAND 连接
        else:
            while len(tmp) > 1:
                t1 = tmp.pop()
                t2 = tmp.pop()
                tmp.append(nand_gate(t1, t2))
    # 输出最终的电路图
    circ += tmp

    return len(circ), '\n'.join(circ)