CSP 202009-3 点亮数字人生

本文介绍了一个数字电路模拟程序,采用递归分治策略实现。通过记忆化搜索提高计算效率,并检查电路中是否存在反馈环路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值