csp20-09-3点亮数字人生-20到100分充满教训版

这道题我做了很久,最初是“错误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;
} 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值