#include <iostream>
#include <cstdio>
#include <string> // substr c_str
#include <vector>
#include <cstdlib> // atoi
#include <cstring> // memset
#include <queue>
using namespace std;
#define mm(a) memset(a, 0, sizeof(a))
const int MAXN = 510;
// 器材结构体
struct item{
string func; // 功能
int k; // 输入数量
vector<int> L; // 输入端描述
};
int Q, M, N; // 问题数 电路输入数量 器件数量
int S; // 运行次数
struct item items[MAXN]; // 记录器材, 注意每个问题清空
int outs[MAXN]; // 记录器材输出结果, 注意每个问题清空
// 给定功能、输入编号(1~N为器材, N+1~N+M为输入信号)、输入信号, 计算功能结果
int funcc(string func, vector<int> v, vector<int> ins){
// 编号转具体输入值
for (int i = 1; i < v.size(); i++){
// 器材输出
if (v[i] <= N) v[i] = outs[v[i]];
// 输入信号
else v[i] = ins[v[i]-N];
}
int res = v[1];
if (func == "NOT") res = !res;
else if (func == "AND") for (int i = 2; i < v.size(); i++) res &= v[i];
else if (func == "OR") for (int i = 2; i < v.size(); i++) res |= v[i];
else if (func == "XOR") for (int i = 2; i < v.size(); i++) res ^= v[i];
else if (func == "NAND"){
for (int i = 2; i < v.size(); i++) res &= v[i];
res = !res;
}
else if (func == "NOR"){
for (int i = 2; i < v.size(); i++) res |= v[i];
res = !res;
}
return res;
}
// 给定一组输入, 按拓扑排序计算运行结果
void runn(vector<int> ins, vector<int> tpcal){
for (int i = 1; i < tpcal.size(); i++){
// 当前计算的器材
int cur = tpcal[i];
// 当前器材的输出
outs[cur] = funcc(items[cur].func, items[cur].L, ins);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> Q;
//依次处理问题
while (Q--){
cin >> M >> N;
int cnt[510]; //统计每个结点的入度
mm(cnt);
vector<int> v[MAXN]; //存储后继
// 器材输入描述初始化
for (int i = 1; i <= N; i++) items[i].L.clear();
// 器材输出初始化
mm(outs);
for (int i = 1; i <= N; i++){
cin >> items[i].func >> items[i].k;
string l;
items[i].L.push_back(0); // 输入从下标1开始存储
for (int _ = 1; _ <= items[i].k; _++){
cin >> l;
int idx; // 器材或输入信号编号
// 输入信号, 从N+1开始
if (l[0] == 'I') idx = N+atoi(l.substr(1).c_str());
// 器材输出
else idx = atoi(l.substr(1).c_str());
items[i].L.push_back(idx); // 存储当前器材的输入
v[idx].push_back(i); // 存入后继
cnt[i]++; // 入度增加
}
}
queue<int> tpq; // 拓扑排序队列
vector<int> tpcal; // 由拓扑排序得到的器材计算顺序
tpcal.push_back(0); // 从下标1开始存储
// 所有输入信号入度为0, 入列
for (int i = N+1; i <= N+M; i++) tpq.push(i);
int times = 0; //记录弹出结点个数
while (!tpq.empty()){
int now = tpq.front(); // 取第一个入度为0的结点
tpq.pop(); // 弹出
times++;
for (int i = 0; i < v[now].size(); i++){
cnt[v[now][i]]--; // 当前结点所有后继结点入度减一
if (cnt[v[now][i]] == 0){
tpq.push(v[now][i]);
tpcal.push_back(v[now][i]);
}
}
}
cin >> S;
vector<vector<int> > inputt(S+5); // 存储输入值
for (int i = 1; i <= S; i++){
int inn; // 每个输入值
inputt[i].push_back(0); // 输入从下标1开始存储
for (int _ = 1; _ <= M; _++){
cin >> inn;
inputt[i].push_back(inn);
}
}
int si; // 输出信号数量
vector<vector<int> > outputt(S+5); // 存储输出信号数量及相应输出器材编号
for (int i = 1; i <= S; i++){
cin >> si;
// 下标0存储输出信号数量, 输出器材编号从下标1开始存储
outputt[i].push_back(si);
int outt;
for (int _ = 1; _ <= si; _++){
cin >> outt;
outputt[i].push_back(outt);
}
}
// 闭环
if (times != M+N) cout << "LOOP" << endl;
else {
// 计算每次运行结果
for (int i = 1; i <= S; i++){
runn(inputt[i], tpcal);
// 输出运行结果
cout << outs[outputt[i][1]];
for (int j = 2; j <= outputt[i][0]; j++)
cout << " " << outs[outputt[i][j]];
cout << endl;
}
}
}
return 0;
}
【CSP】202009-3 点亮数字人生 拓扑排序 模拟
最新推荐文章于 2024-03-23 14:28:43 发布