CSP202009-3 点亮数字人生(拓扑排序)

Posted 脂环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSP202009-3 点亮数字人生(拓扑排序)相关的知识,希望对你有一定的参考价值。

不难的大模拟,思路就是拓扑排序或者dfs判环,需要注意的是当一个点入度为0,说明邻接到它的点的值已经计算出来了,这时候就可以计算这个点的值了。

坑点:当为loop的时候不能break,而是应该设置标记,然后把剩下的数据都读入(不作处理),最后输出一个loop。在这里卡了两个多小时。。

#include <bits/stdc++.h>
using namespace std;
int Q, M, N, S;
struct node {
	int id, func, k;
	vector<int> I, O, out;
} e[100005];
int deg[100005], orideg[100005];
int tran(string s) {
	int ans = 0;
	for(int i = 0; i < s.size(); i++) {
		ans *= 10;
		ans += (s[i] - \'0\');
	}
	return ans;
}
int result[100005];
queue<int> q;
void calc(int id) {
	if(!e[id].k) return;//k为0是输入 result已经有值了 直接返回
	if(e[id].func == 1) {
		if(e[id].I.size()) {
			result[id] = !result[e[id].I[0]];
		} else {
			result[id] = !result[e[id].O[0]];
		}
	} else if(e[id].func == 2) {
		int ans = 1;
		for(auto x : e[id].I) ans = ans & result[x];
		for(auto x : e[id].O) ans = ans & result[x];
		result[id] = ans;
	} else if(e[id].func == 3) {
		int ans = 0;
		for(auto x : e[id].I) ans = ans | result[x];
		for(auto x : e[id].O) ans = ans | result[x];
		result[id] = ans;
	} else if(e[id].func == 4) {
		int ans = -1;
		for(auto x : e[id].I) {
			if(ans == -1) ans = result[x];
			else ans = ans ^ result[x];
		}
		for(auto x : e[id].O) {
			if(ans == -1) ans = result[x];
			else ans = ans ^ result[x];
		}
		result[id] = ans;
	} else if(e[id].func == 5) {
		int ans = 1;
		for(auto x : e[id].I) ans = ans & result[x];
		for(auto x : e[id].O) ans = ans & result[x];
		result[id] = !ans;
	} else {
		int ans = 0;
		for(auto x : e[id].I) ans = ans | result[x];
		for(auto x : e[id].O) ans = ans | result[x];
		result[id] = !ans;
	}
}
int main() {
	cin >> Q;
	while(Q--) {
		cin >> M >> N;
		bool loop = 0;
		memset(orideg, 0, sizeof(orideg));
		memset(deg, 0, sizeof(deg));
		memset(result, 0, sizeof(result));
		while(q.size()) q.pop();
		for(int i = 0; i <= N + M + 5; i++) e[i].k = 0, e[i].id = i, e[i].I.clear(), e[i].O.clear(), e[i].out.clear();
		for(int i = 1; i <= N; i++) {
			string FUNC;
			int k;
			cin >> FUNC;
			cin >> k;
			e[i].k = k;
			if(FUNC == "NOT") e[i].func = 1;
			else if(FUNC == "AND") e[i].func = 2;
			else if(FUNC == "OR") e[i].func = 3;
			else if(FUNC == "XOR") e[i].func = 4;
			else if(FUNC == "NAND") e[i].func = 5;
			else e[i].func = 6;
			for(int j = 1; j <= k; j++) {
				string tmp;
				cin >> tmp;
				int id = tran(tmp.substr(1));
				if(tmp[0] == \'I\') {
					e[i].I.push_back(N + id);
					e[N + id].out.push_back(i);
					orideg[i]++;
				} else {
					e[i].O.push_back(id);
					e[id].out.push_back(i);
					orideg[i]++;
				}
			}
		}
		cin >> S;
		vector<vector<int> > v(S);
		for(int i = 1; i <= S; i++) {
			for(int j = 1; j <= M; j++) {
				int tmp;
				cin >> tmp;
				v[i - 1].push_back(tmp);
			}
		}
		//cout << M << endl;
		for(int i = 1; i <= S; i++) {
			int s;
			cin >> s;
			for(int j = 1; j <= N + M; j++) {
				deg[j] = orideg[j];
				result[i] = 0;
			}
			while(q.size()) q.pop();
			for(int j = 0; j < v[i - 1].size(); j++) {
				result[N + j + 1] = v[i - 1][j];
				q.push(j + 1 + N);//M个输入对应的节点入队
			}
			bool vis[5005];
			for(int j = 1; j <= N + M; j++) vis[j] = 0;
			int cnt = 0;
			while(q.size()) {
				if(loop) break;
				int now = q.front(); q.pop();
				calc(now);//计算它的result
				for(auto x : e[now].out) {
					deg[x]--;
					if(deg[x] == 0 && (!vis[x])) {
						q.push(x);
						vis[x] = 1;
						cnt++;
					}
				}
			}
			if(cnt != N) {
				loop = 1;
				for(int j = 1; j <= s; j++) {
					int useless;
					cin >> useless;
				}
			} else {
				for(int j = 1; j <= s; j++) {
					int query;
					cin >> query;
					cout << result[query] << " ";
				}
				cout << endl;
			}
		}
		if(loop) puts("LOOP");
	}
	return 0;
}

以上是关于CSP202009-3 点亮数字人生(拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

CSP模拟赛益智游戏(最短路&拓扑排序)

2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine强联通缩点+拓扑排序((代

CSP-S 2019 游记

[考试反思]1102csp-s模拟测试98:苟活

CSP-S 模拟(b)