CSP202009-3 点亮数字人生

该博客详细解析了一道关于图论和电路模拟的CSP竞赛题目,涉及图论节点数据结构、拓扑排序、逻辑门器件模拟等。博主首先介绍了如何将逻辑器件抽象成图论节点,接着讲解了主函数如何读取输入、建立图并判断环。拓扑排序用于检测环的存在,若发现环则输出'LOOP',否则模拟电路输出器件状态。此外,还提供了六种逻辑门器件的工作代码实现。

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

题目

题目可以在CSP的官网上找到哟!

算法思想

这道题看上去花里胡哨的,其实本质上是一个有关图论和小模拟的题目,模拟规模不大,所涉及到的图论的难度也不高。题目首先要求查看是否出现带环的电路,我们可以将逻辑器件抽象成图论中的节点,然后通过拓扑排序即可判断是否出现环。如果出现环,则直接输出“LOOP”即可;如果没有出现环,则根据输入形式按照输出形式,输出需要的器件的状态,这个可以从所需要的节点进行递归调用,求解出器件的状态值。
结果

代码详解

1、图论节点数据结构

每一个逻辑门器件都抽象成图论中的节点,具体代码如下:

struct node
{
	int type;       //节点种类对应着不同种类的器件 
	int output;     //器件的输出状态值
	int input_num;  //连接该器件的输入信号数量
	int input[6];   //存储连接该器件的输入信号的序号
}Node[3005];
2、主函数

主函数的功能主要是按照输入格式将输入信息读取出来,并按照信号的连接方式进行建图,建图之后首先判断是否含有环,是用拓扑排序的思想进行判断环,如果存在环,则直接输出"LOOP"即可;如果不存在环,则按照输出格式的要求,运行电路,输出所需要的器件的状态值。
具体的代码如下:

int main()
{
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
	int ii, i, j, k;
	cin >> q;          
	for (ii = 1; ii <= q; ii++)
	{
		cin >> m >> n;
		for (i = 0; i < m; i++)
		{
			Node[i].type = 0;
			Node[i].output = -1;
		}
		memset(d, 0, sizeof(d));
		for (i = 0; i < n; i++)
		{
			Node[m + i].output = -1;
			string fun_type;
			cin >> fun_type;
			//区分不同种类的器件
			if (fun_type == "NOT") {
				Node[m + i].type = 1;
			}
			else if (fun_type == "AND") {
				Node[m + i].type = 2;
			}
			else if (fun_type == "OR") {
				Node[m + i].type = 3;
			}
			else if (fun_type == "XOR") {
				Node[m + i].type = 4;
			}
			else if (fun_type == "NAND") {
				Node[m + i].type = 5;
			}
			else if (fun_type == "NOR") {
				Node[m + i].type = 6;
			}
			int fun_num;
			cin >> fun_num;
			Node[m + i].input_num = fun_num;
			for (j = 0; j < fun_num; j++)   //存储器件的输入信号
			{
				string input_num;
				cin >> input_num;
				int num = 0;
				for (k = 1; k < input_num.length(); k++)
					num = num * 10 + (input_num[k] - '0');
				if (input_num[0] == 'I') {
					Node[m + i].input[j] = num - 1;
				}
				else if (input_num[0] == 'O') {
					Node[m + i].input[j] = num - 1 + m;
					d[num - 1]++;
				}
			}
		}
		cin >> s;
		for (i = 0; i < s; i++)
		{
			for (j = 0; j < m; j++)
			{
				cin >> inp[i][j];
			}
		}
		int si;
		int oi;
		if (CheckCircle())   //存在环,正常输入,直接输出"LOOP"
		{
			for (i = 0; i < s; i++)
			{
				cin >> si;
				for (j = 0; j < si; j++)
					cin >> oi;
			}
			cout << "LOOP" << endl;
		}
		else  //没有环,继续进行模拟
		{
			for (i = 0; i < s; i++)
			{
				cin >> si;
				for (j = 0; j < m; j++)
					Node[j].output = inp[i][j];
				for (j = 0; j < n; j++)
					Node[m + j].output = -1;
				for (j = 0; j < si; j++)
				{
					cin >> oi;
					cout << work(m + oi - 1) << " ";
				}
				cout << endl;
			}
		}
	}
	return 0;
}
3、拓扑排序判断是否存在环

拓扑排序判断是否有环的主要思想就是:根据建成的图结构,统计每一个节点的入度,将每一个入读为0的节点删去,重新调整其余节点的入度,一直循环下去,如果最后入读全为0,则说明该图形结构中没有环的出现;如果最后有入度不为0的节点,则说明图形结构中出现了环。
具体的代码如下:

int CheckCircle()
{
	int i;
	queue<int>qu;
	bool ans = false;
	for (i = 0; i < n; i++)
		if (d[i] == 0) qu.push(i);
	while (!qu.empty())
	{
		int v = qu.front();
		qu.pop();
		for (i = 0; i < Node[m + v].input_num; i++)
		{
			if (Node[m + v].input[i] >= m)
			{
				d[Node[m + v].input[i] - m]--;
				if (d[Node[m + v].input[i] - m] == 0) qu.push(Node[m + v].input[i] - m);
			}
		}
	}
	for (i = 0; i < n; i++)
		if (d[i] != 0) ans = true;
	return ans;
}
4、电路的模拟

本题中设计到六种逻辑器件的模拟,我们只需要对这六种不同的逻辑器件按照其实际的逻辑功能进行计算即可,具体的代码如下:

int NOTwork(int num)
{
	if (Node[num].output == -1)
		Node[num].output = !work(Node[num].input[0]);
	return Node[num].output;
}
int ANDwork(int num)
{
	int ans = 1, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans & work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int ORwork(int num)
{
	int ans = 0, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans | work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int XORwork(int num)
{
	int ans, i;
	if (Node[num].output == -1)
	{
		ans = work(Node[num].input[0]);
		for (i = 1; i < Node[num].input_num; i++)
		{
			ans = ans ^ work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int NANDwork(int num)
{
	int ans = 1, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans & work(Node[num].input[i]);
		}
		Node[num].output = !ans;
	}
	return Node[num].output;
}
int NORwork(int num)
{
	int ans = 0, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans | work(Node[num].input[i]);
		}
		Node[num].output = !ans;
	}
	return Node[num].output;
}
int work(int num)
{
	if (Node[num].type == 0) {
		return Node[num].output;
	}
	else if (Node[num].type == 1) {
		return NORwork(num);
	}
	else if (Node[num].type == 2) {
		return ANDwork(num);
	}
	else if (Node[num].type == 3) {
		return ORwork(num);
	}
	else if (Node[num].type == 4) {
		return XORwork(num);
	}
	else if (Node[num].type == 5) {
		return NANDwork(num);
	}
	else if (Node[num].type == 6) {
		return NORwork(num);
	}
	else return -1;
}

完整代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#pragma warning (disable:4996)
using namespace std;
int q;
int n, m; //m:输入信号的数量; n:器件数量
int s;
struct node
{
	int type;       //节点种类对应着不同种类的器件 
	int output;     //器件的输出状态值
	int input_num;  //连接该器件的输入信号数量
	int input[6];   //存储连接该器件的输入信号的序号
}Node[3005];
int d[3005];
int inp[10000][10000];
int work(int num);
int CheckCircle()
{
	int i;
	queue<int>qu;
	bool ans = false;
	for (i = 0; i < n; i++)
		if (d[i] == 0) qu.push(i);
	while (!qu.empty())
	{
		int v = qu.front();
		qu.pop();
		for (i = 0; i < Node[m + v].input_num; i++)
		{
			if (Node[m + v].input[i] >= m)
			{
				d[Node[m + v].input[i] - m]--;
				if (d[Node[m + v].input[i] - m] == 0) qu.push(Node[m + v].input[i] - m);
			}
		}
	}
	for (i = 0; i < n; i++)
		if (d[i] != 0) ans = true;
	return ans;
}
int NOTwork(int num)
{
	if (Node[num].output == -1)
		Node[num].output = !work(Node[num].input[0]);
	return Node[num].output;
}
int ANDwork(int num)
{
	int ans = 1, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans & work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int ORwork(int num)
{
	int ans = 0, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans | work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int XORwork(int num)
{
	int ans, i;
	if (Node[num].output == -1)
	{
		ans = work(Node[num].input[0]);
		for (i = 1; i < Node[num].input_num; i++)
		{
			ans = ans ^ work(Node[num].input[i]);
		}
		Node[num].output = ans;
	}
	return Node[num].output;
}
int NANDwork(int num)
{
	int ans = 1, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans & work(Node[num].input[i]);
		}
		Node[num].output = !ans;
	}
	return Node[num].output;
}
int NORwork(int num)
{
	int ans = 0, i;
	if (Node[num].output == -1)
	{
		for (i = 0; i < Node[num].input_num; i++)
		{
			ans = ans | work(Node[num].input[i]);
		}
		Node[num].output = !ans;
	}
	return Node[num].output;
}
int work(int num)
{
	if (Node[num].type == 0) {
		return Node[num].output;
	}
	else if (Node[num].type == 1) {
		return NORwork(num);
	}
	else if (Node[num].type == 2) {
		return ANDwork(num);
	}
	else if (Node[num].type == 3) {
		return ORwork(num);
	}
	else if (Node[num].type == 4) {
		return XORwork(num);
	}
	else if (Node[num].type == 5) {
		return NANDwork(num);
	}
	else if (Node[num].type == 6) {
		return NORwork(num);
	}
	else return -1;
}
int main()
{
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
	int ii, i, j, k;
	cin >> q;          
	for (ii = 1; ii <= q; ii++)
	{
		cin >> m >> n;
		for (i = 0; i < m; i++)
		{
			Node[i].type = 0;
			Node[i].output = -1;
		}
		memset(d, 0, sizeof(d));
		for (i = 0; i < n; i++)
		{
			Node[m + i].output = -1;
			string fun_type;
			cin >> fun_type;
			//区分不同种类的器件
			if (fun_type == "NOT") {
				Node[m + i].type = 1;
			}
			else if (fun_type == "AND") {
				Node[m + i].type = 2;
			}
			else if (fun_type == "OR") {
				Node[m + i].type = 3;
			}
			else if (fun_type == "XOR") {
				Node[m + i].type = 4;
			}
			else if (fun_type == "NAND") {
				Node[m + i].type = 5;
			}
			else if (fun_type == "NOR") {
				Node[m + i].type = 6;
			}
			int fun_num;
			cin >> fun_num;
			Node[m + i].input_num = fun_num;
			for (j = 0; j < fun_num; j++)   //存储器件的输入信号
			{
				string input_num;
				cin >> input_num;
				int num = 0;
				for (k = 1; k < input_num.length(); k++)
					num = num * 10 + (input_num[k] - '0');
				if (input_num[0] == 'I') {
					Node[m + i].input[j] = num - 1;
				}
				else if (input_num[0] == 'O') {
					Node[m + i].input[j] = num - 1 + m;
					d[num - 1]++;
				}
			}
		}
		cin >> s;
		for (i = 0; i < s; i++)
		{
			for (j = 0; j < m; j++)
			{
				cin >> inp[i][j];
			}
		}
		int si;
		int oi;
		if (CheckCircle())   //存在环,正常输入,直接输出"LOOP"
		{
			for (i = 0; i < s; i++)
			{
				cin >> si;
				for (j = 0; j < si; j++)
					cin >> oi;
			}
			cout << "LOOP" << endl;
		}
		else  //没有环,继续进行模拟
		{
			for (i = 0; i < s; i++)
			{
				cin >> si;
				for (j = 0; j < m; j++)
					Node[j].output = inp[i][j];
				for (j = 0; j < n; j++)
					Node[m + j].output = -1;
				for (j = 0; j < si; j++)
				{
					cin >> oi;
					cout << work(m + oi - 1) << " ";
				}
				cout << endl;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值