📌  相关文章
📜  门| Sudo GATE 2020 Mock III(2019年1月24日)|问题27(1)

📅  最后修改于: 2023-12-03 15:42:19.985000             🧑  作者: Mango

门 | Sudo GATE 2020 Mock III (2019年1月24日) | 问题 27

题目描述

在一个布尔代数中,有一个逻辑门,它有两个输入和一个输出。这个逻辑门有一个开关控制输入。 当开关关闭时,逻辑门的输出始终为1。 开关打开时,逻辑门的输出等价于其两个输入之间的逻辑AND关系。现在,如果这样的逻辑门被用于构建连接元素的线路,那么实现相同的线路所需的逻辑门的数量,如果开关被按下,则会______。(在编写程序时使用关键字进行回答)

给定N个输入,从左到右标记为1, 2,..., N和单个开关。在输入1和开关之间有一个逻辑门。对于 i(1≤i≤N−1),第 i 个输入与第 i+1 输入之间有一个逻辑门。 在第 N 个输入和输出之间也有一个逻辑门。你的任务是为这些逻辑门计算最大值和最小值,这取决于开关是否打开。

例如:

考虑三个输入和一个开关,

A1 A2 A3 [SW] Out

那么以下两种线路可能被实现,

  • 线路-1

    A1-->AND-->A2-->AND-->A3-->AND-->(SW)-->Out
    
    • 打开开关时,输出为 A1 AND A2 AND A3
    • 关闭开关时,输出恒为 1
  • 线路-2

    A1-->AND-->A2-->AND-->A3-->(SW)-->AND-->Out
    
    • 打开开关时,输出为 A1 AND A2 AND A3
    • 关闭开关时,输出为 0

计算下述输入线路的最小和最大输出:

A1 A2 ... AN [SW] Out
思路

对于给定的 $n$ 个输入和开关, 假设我们选择使每个相邻的两个输入和逻辑门之间的逻辑门类型相同. 如果开关被按下,则在每对相邻输入之间, 逻辑门的类型为 AND;否则, 逻辑门的类型为 OR

这个题目的解法和递推式如下.

记 $D_{i,0}$ 表示 $[1, i]$ 区间内的最小值, $D_{i,1}$ 表示 $[1, i]$ 区间内的最大值.

初始化: $D_{1,0} = D_{1,1} = A_1$

对于 $i \in [2,n]$, 计算 $D_{i,0}, D_{i,1}$:

  • 如果 SW 为开启状态, 则 $D_{i,0} = 1$;
  • 否则,
    • 当 $i$ 为偶数时, $D_{i,0} = D_{i-1,0} \texttt{ OR } A_i$, $D_{i,1} = D_{i-1,1} \texttt{ AND } A_i$;
    • 当 $i$ 为奇数时, $D_{i,0} = D_{i-1,0} \texttt{ AND } A_i$, $D_{i,1} = D_{i-1,1} \texttt{ OR } A_i$.
  • 对于 $i \in (2, n]$, 如果 SW 为关闭状态, 则更新 $D_{i,1}$ 为 $0$.

最终输出为 $D_{n, 1}, D_{n, 0}$.

时间复杂度是 $O(n)$.

代码实现

C++代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int N = 10010;
int a[N], d[N][2];

int main() {
    int n, sw; cin >> n;
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    scanf("%d", &sw);

    // 初始化
    d[1][0] = d[1][1] = a[1];

    for(int i = 2; i <= n; i++) {
        if(sw) d[i][0] = 1;
        else if(i % 2 == 0) {
            d[i][0] = d[i - 1][0] | a[i];
            d[i][1] = d[i - 1][1] & a[i];
        } else {
            d[i][0] = d[i - 1][0] & a[i];
            d[i][1] = d[i - 1][1] | a[i];
        }
        if(!sw && i > 2 && i % 2 == 1) 
            d[i][1] = 0;
    }

    printf("%d %d\n", d[n][0], d[n][1]);
    return 0;
}

python代码:

n = int(input().strip())
a = list(map(int, input().split()))
sw = int(input().strip())

# 初始化
d = [[0, 0] for _ in range(n + 1)]
d[1][0] = d[1][1] = a[0]

# 计算结果
for i in range(2, n + 1):
    if (sw == 1):
        d[i][0] = 1;
    elif (i % 2 == 0):
        d[i][0] = d[i - 1][0] | a[i - 1]
        d[i][1] = d[i - 1][1] & a[i - 1]
    else:
        d[i][0] = d[i - 1][0] & a[i - 1]
        d[i][1] = d[i - 1][1] | a[i - 1]

    # 关闭开关时, 偶数时的最小值是 0
    if (sw == 0 and i % 2 == 1 and i > 2):
        d[i][1] = 0

print(d[n][0], d[n][1])

注意: 本人对原程序进行了一点点更改以符合markdown要求。