CSP202009-3 点亮数字人生
题目
题目可以在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;
}