// simulate 数字电路,核心思想: 递归调用的分治策略
// Specifically,某个器件 i 的输出是 func_i(func_j, func_q, ..., func_r),
// 也就是说 func_j, func_q, ..., func_r 的输入会送到 func_i 的输出,as 直接性的信息
// 本程序使用 calculate() 函数来充当 func_i,其余信息都以参数的形式进行传递
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
using namespace std;
int * tmp; // 记忆化搜索求快
int parse_str(string str) { // 例如将 "I233" or "O233" 返回成 233
int result = 0;
for (int i = 1; i < str.size(); i++) {
result *= 10;
result += str[i] - '0';
}
return result;
}
/* visited[] 用来剪枝,已考察过的不必考察 */
bool judgeLoop(string** unit, int* input_num, int N) {
// 如果每个器件(for i from 1 to N),都在输入的方向通路上找不到自己,则无环
// 如果某一时刻找到了自己,则有环
vector<int> stack;
bool* visited = new bool[N + 1]();
for (int i = 1; i <= N; i++) {
stack.push_back(i);
while (!stack.empty()) {
int which = stack[0];
stack.erase(stack.begin());
visited[which] = true;
for (int j = 1; j <= input_num[which]; j++) {
if (unit[which][j][0] == 'I') continue; //遇到了整体的输入信号,走出了出去
int w = parse_str(unit[which][j]);
if (w == i) return true; // 遇到了本次考察的初始点,有环
if (visited[w]) continue; // 遇到了以前考察过的,不必再考察
stack.push_back(w);
}
} // while 正常跳出,表明器件 i 向输入端方向找是无环的
memset(visited, 0, N+1); // 再把检测环用的 visited 数组重新赋值全 0
}
return false;
}
int calculate(string ** unit, int * input_num, int * inputs, int which) {
int result = 0; // result = ... either 0 or 1 in the end
if (unit[which][0] == "NOT") {
int w = parse_str(unit[which][1]);
if (unit[which][1][0] == 'I') result = !inputs[w];
else {
if (tmp[w] == -1)
result = !calculate(unit, input_num, inputs, w);
else
result = !tmp[w];
}
}
else if (unit[which][0] == "AND") {
result = 1;
for (int j = 1; j <= input_num[which]; j++) {
int w = parse_str(unit[which][j]);
if (unit[which][j][0] == 'I') result &= inputs[w];
else {
if (tmp[w] == -1)
result &= calculate(unit, input_num, inputs, w);
else
result &= tmp[w];
}
}
}
else if (unit[which][0] == "OR") {
result = 0;
for (int j = 1; j <= input_num[which]; j++) {
int w = parse_str(unit[which][j]);
if (unit[which][j][0] == 'I') result |= inputs[w];
else {
if (tmp[w] == -1)
result |= calculate(unit, input_num, inputs, w);
else
result |= tmp[w];
}
}
}
else if (unit[which][0] == "XOR") {
int w = parse_str(unit[which][1]);
if (unit[which][1][0] == 'I') result = inputs[w];
else {
if (tmp[w] == -1)
result = calculate(unit, input_num, inputs, w);
else
result = tmp[w];
}
for (int j = 2; j <= input_num[which]; j++) {
int w = parse_str(unit[which][j]);
if (unit[which][j][0] == 'I') result ^= inputs[w];
else {
if (tmp[w] == -1)
result ^= calculate(unit, input_num, inputs, w);
else
result ^= tmp[w];
}
}
}
else if (unit[which][0] == "NAND") {
result = 1;
for (int j = 1; j <= input_num[which]; j++) {
int w = parse_str(unit[which][j]);
if (unit[which][j][0] == 'I') result &= inputs[w];
else {
if (tmp[w] == -1)
result &= calculate(unit, input_num, inputs, w);
else
result &= tmp[w];
}
}
result = !result;
}
else if (unit[which][0] == "NOR") {
result = 0;
for (int j = 1; j <= input_num[which]; j++) {
int w = parse_str(unit[which][j]);
if (unit[which][j][0] == 'I') result |= inputs[w];
else {
if (tmp[w] == -1)
result |= calculate(unit, input_num, inputs, w);
else
result |= tmp[w];
}
}
result = !result;
}
tmp[which] = result; // 中间结果记忆化
return result;
}
int main() {
int Q;
cin >> Q;
int*** result = new int** [Q + 1](); // result[q] 记录第 q 个 out_unit
bool* haveLoop = new bool[Q + 1]();
int* SS = new int[Q + 1](); // S[q] 记录问题 q 有 多少个查询
int** result_num = new int*[Q + 1](); // result_num[q] 记录第 q 个 out_num
for (int q = 1; q <= Q; q++) {
int M, N; // M: input_number. N: unit_number
cin >> M >> N;
tmp = new int[N + 1](); // 存储器件 i 的输出,供其他器件输入查用
string** unit = new string * [N + 1](); // unit[i] 记录器件 i 的输入信息
int* input_num = new int[N + 1](); // input_num[i] 是指器件 i 的输入数量
for (int i = 1; i <= N; i++) {
string operation;
cin >> operation >> input_num[i];
unit[i] = new string[input_num[i] + 1]();
unit[i][0] = operation; // unit[i][0] 记录操作类型(器件功能)
for (int j = 1; j <= input_num[i]; j++)
cin >> unit[i][j]; // unit[i][p] 是器件 i 的第 j 个输入
} // end construct units from 1 to N
if (judgeLoop(unit, input_num, N))
haveLoop[q] = true;
int S;
cin >> S;
SS[q] = S;
int** input = new int*[S + 1]();
for (int s = 1; s <= S; s++) { // 一共有 S 次查询(也必然是 S 次输出)
input[s] = new int[M + 1]();
for (int m = 1; m <= M; m++) // 每次查询有 M 个输入信号(对于整体的输入信号)
cin >> input[s][m];
}
int** out_unit = new int* [S + 1](); // out_unit[s]记录第 s 个查询的结果
int* out_num = new int[S + 1](); // out_num[s] 记录第 s 个查询结果包括多少个器件
int num;
int which;
for (int s = 1; s <= S; s++) {
for (int i = 1; i <= N; i++) tmp[i] = -1;
cin >> out_num[s];
num = out_num[s];
out_unit[s] = new int[num + 1];
for (int j = 1; j <= num; j++) { // 第 s 个查询的第 j 个器件
cin >> which;
if (haveLoop[q]) continue;
out_unit[s][j] = calculate(unit, input_num, input[s], which);
}
} // 输入信号与查询命令 Done
result[q] = out_unit;
result_num[q] = out_num;
}
for (int q = 1; q <= Q; q++) {
if (haveLoop[q]) {
cout << "LOOP" << endl;
continue;
}
int** out_unit = result[q];
int* out_num = result_num[q];
for (int s = 1; s <= SS[q]; s++) {
for (int j = 1; j <= out_num[s]; j++)
cout << out_unit[s][j] << ' ';
cout << endl;
}
}
return 0;
}
CSP 202009-3 点亮数字人生
最新推荐文章于 2021-12-27 20:25:29 发布