这道题我做了很久,最初是“错误0分”,后面去查看了其他的测试样例才发现我对输入的取反用的~,应该用!来对位取反,因为我代码中设置的输入为Int型,取反的话会等于-1。因为这个坑我一直都是错误,后来把这个地方改掉之后就是运行超时20分,现在去学习一下如何优化。这道题最开始我连判断环路都不会,但是学习到了通过拓扑排序入度来解决,先记录一下超时的20分版吧。
//2009-3点亮数字人生---运行超时20分版
#include<bits/stdc++.h>
using namespace std;
int cnt = 0; // 记录门电路的输出
// 门电路结构--不与具体输入结合以便在一个问题内不需要刷新
struct Door {
string type; // 门电路类型
int innum; // 输入个数
int output; // 输出
vector<int> input; // 原输入编号
vector<int> out; // 拓扑排序用
}door[505];
int m, n, s;
vector<int> in[505]; // 存储输入数据--初始化为-1
int rudu[505];
int judge(int x) { // 检测器件n是否输入完成
if(in[x].size()!=door[x].innum) return 0;
return 1;
}
// 具体操作
void cal(int i) {
// 检查输入是否都到位
// cout << "11" <<endl;
if(judge(i)&&door[i].output==-1) {
// cout << "22" << endl;
cnt++;
door[i].output = in[i][0];
// 进行具体运算
if(door[i].type=="NOT") {
door[i].output = !door[i].output;
}
else if(door[i].type=="AND" || door[i].type=="NAND") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output&in[i][j];
}
if(door[i].type=="NAND") door[i].output = !door[i].output;
}
else if(door[i].type=="OR"||door[i].type=="NOR") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output|in[i][j];
}
if(door[i].type=="NOR") door[i].output = !door[i].output;
}
else if(door[i].type=="XOR") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output^in[i][j];
}
}
// 操作结束,对下一输入进行赋值
for(auto& it:door[i].out) {
in[it].push_back(door[i].output);
}
}
return;
}
vector<int> ss[10005]; // 存s次输入样例
vector<int> si[10005]; // 存输入规格
// 将func中的输入转化成具体数字
int chuli(int n, string str) { // 第n个器件的输入处理
char ch = str[0];
str = str.substr(1); // 去掉开始的I,O
// 将str转化成十进制
int sum=0;
for(int i=0; i<str.length(); i++) {
sum *= 10;
sum += str[i]-'0';
}
if(ch=='I') {
door[n].input.push_back(sum);
}
else if(ch=='O') {
rudu[n]++; // 入度加1
door[sum].out.push_back(n);
}
}
// 拓扑排序判断环路
int huan() {
int aa = 0;
// 建立队列
queue<int> q;
for(int i=1; i<=n; i++) {
if(rudu[i]==0) q.push(i); // 将入度为0的元素加入
}
while(!q.empty()) {
int index = q.front();
q.pop(); // 出队
aa++;
for(auto it:door[index].out) {
rudu[it]--;
if(rudu[it]==0) q.push(it);
}
}
// 如果最终入度都为0,则不存在环路
if(aa==n) return 0;
else return 1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int q, k;
cin >> q;
while(q--) { // q个问题
// 对器件进行清零
for (int i = 0; i < 505; i++) {
door[i].type = "";
door[i].innum = 0;
door[i].output = -1;
door[i].input.clear();
}
// 入度记录清0
fill(rudu, rudu+505, 0);
// for(int i=0; i<505; i++) rudu[i] = 0;
cin >> m >> n;
// 读取电路结构
for(int i=1; i<=n; i++) {
cin >> door[i].type;
cin >> k;
door[i].innum = k;
while(k--) {
string op;
cin >> op;
chuli(i, op);
}
}
// 读取输入样例和输出规格
cin >> s;
for(int i=0; i<s; i++) {
for(int j=0; j<m; j++) {
int x; cin >> x;
ss[i].push_back(x);
}
}
for(int i=0; i<s; i++) {
int t;
cin >> t;
for(int j=0; j<t; j++) {
int x; cin >> x;
si[i].push_back(x);
}
}
// 判断是否为环路
if(huan()) cout << "LOOP" << endl;
else { // 没有环路,计算s次输入结果
// 计算s次输出
for(int i=0; i<s; i++) {
cnt = 0; // 清零
// --------运算--------
// 将原始输入放入门电路中
for(int j=1; j<=n; j++) {
in[j].clear(); // 将之前的数据清零
door[j].output = -1; // 将门电路的output清零
for(auto tt:door[j].input) {
in[j].push_back(ss[i][tt-1]);
}
}
while(cnt<n) {
for(int j=1; j<=n; j++) {
cal(j); // 器件j进行运算
}
}
// 输出
for(auto it:si[i]) {
cout << door[it].output << " ";
}
cout << endl;
}
}
}
return 0;
}
这里的运行超时我在评论区已经说过了,通过de这个bug让我真的对拓扑排序有了很深的印象!!既然判环都得出了拓扑序列,后面既然都没用!真的脑子不好!改掉这个错误之后,运行就正确了,但是一直停留在20分,看了好多好多题解,找到了一个和我错误类似的博主,我才意识到我在每个问题之后对数据的清零没有做到位!遗漏了一些清零处理!改掉之后就ac了。这道题真的!总结起来就是思路很简单(除了拓扑排序那,图论的知识我不太会,但是之后会了!!),就是对于数据的处理和保存、清零一定要小心,很少遇到这种数据量很大且重复的题!吸取了很多经验!把ac的代码放在下面啦!
//2009-3点亮数字人生---运行超时20分版
#include<bits/stdc++.h>
using namespace std;
// 门电路结构--不与具体输入结合以便在一个问题内不需要刷新
struct Door {
string type; // 门电路类型
int innum; // 输入个数
int output; // 输出
vector<int> input; // 原输入编号
vector<int> out; // 拓扑排序用
}door[505];
int m, n, s;
vector<int> in[505]; // 存储输入数据--初始化为-1
int rudu[505];
vector<int> tra; // 记录拓扑序列
vector<int> ss[10005]; // 存s次输入样例
vector<int> si[10005]; // 存输入规格
// 具体操作
void cal(int i) {
door[i].output = in[i][0];
// 进行具体运算
if(door[i].type=="NOT") {
door[i].output = !door[i].output;
}
else if(door[i].type=="AND" || door[i].type=="NAND") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output&in[i][j];
}
if(door[i].type=="NAND") door[i].output = !door[i].output;
}
else if(door[i].type=="OR"||door[i].type=="NOR") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output|in[i][j];
}
if(door[i].type=="NOR") door[i].output = !door[i].output;
}
else if(door[i].type=="XOR") {
for(int j=1; j<door[i].innum; j++) {
door[i].output = door[i].output^in[i][j];
}
}
// 操作结束,对下一输入进行赋值
for(auto& it:door[i].out) {
in[it].push_back(door[i].output);
}
return;
}
// 将func中的输入转化成具体数字
int chuli(int n, string str) { // 第n个器件的输入处理
char ch = str[0];
str = str.substr(1); // 去掉开始的I,O
// 将str转化成十进制
int sum=0;
for(int i=0; i<str.length(); i++) {
sum *= 10;
sum += str[i]-'0';
}
if(ch=='I') {
door[n].input.push_back(sum);
}
else if(ch=='O') {
rudu[n]++; // 入度加1
door[sum].out.push_back(n);
}
}
// 拓扑排序判断环路
int huan() {
int aa = 0;
// 建立队列
queue<int> q;
for(int i=1; i<=n; i++) {
if(rudu[i]==0) q.push(i), tra.push_back(i); // 将入度为0的元素加入
}
while(!q.empty()) {
int index = q.front();
q.pop(); // 出队
aa++;
for(auto it:door[index].out) {
rudu[it]--;
if(rudu[it]==0) q.push(it), tra.push_back(it);
}
}
// 如果最终入度都为0,则不存在环路
if(aa==n) return 0;
else return 1;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int q, k;
cin >> q;
while(q--) { // q个问题
// 对器件进行清零
for (int i = 0; i < 505; i++) {
door[i].type = "";
door[i].innum = 0;
door[i].output = -1;
door[i].input.clear();
door[i].out.clear();
}
// 入度记录清0
fill(rudu, rudu+505, 0);
tra.clear();
cin >> m >> n;
// 读取电路结构
for(int i=1; i<=n; i++) {
cin >> door[i].type;
cin >> k;
door[i].innum = k;
while(k--) {
string op;
cin >> op;
chuli(i, op);
}
}
// 读取输入样例和输出规格
cin >> s;
for(int i=0; i<s; i++) {
ss[i].clear();
si[i].clear();
}
for(int i=0; i<s; i++) {
for(int j=0; j<m; j++) {
int x; cin >> x;
ss[i].push_back(x);
}
}
for(int i=0; i<s; i++) {
int t;
cin >> t;
for(int j=0; j<t; j++) {
int x; cin >> x;
si[i].push_back(x);
}
}
// 判断是否为环路
if(huan()) cout << "LOOP" << endl;
else { // 没有环路,计算s次输入结果
// 计算s次输出
for(int i=0; i<s; i++) {
// --------运算--------
// 将原始输入放入门电路中
for(int j=1; j<=n; j++) {
in[j].clear(); // 将之前的数据清零
door[j].output = -1; // 将门电路的output清零
for(auto tt:door[j].input) {
in[j].push_back(ss[i][tt-1]);
}
}
for(auto tt:tra) {
cal(tt);
}
// 输出
for(auto it:si[i]) {
cout << door[it].output << " ";
}
cout << endl;
}
}
}
return 0;
}