【CSP】点亮数字人生(202009)

1. 分析

在这里插入图片描述

正确的解题思路:

  • 拓扑排序(Topological Sort)
    使用拓扑排序确定处理电路门的顺序。
  • 大模拟
    使用与(&)、或(|)、非(!)、异或(^)等操作模拟电路门,由输入信号得出输出信号。
  • 作用域
    这道题的输入格式很奇怪。先输入所有问题的电路门的结构,再输入所有问题的电路门的输入,最后输入所有的问题要输出的电路门编号。而不是一个个问题输入。
    多次处理同一个问题时,巧妙地利用作用域(例如,将整个问题抽象成函数,将所有所需的变量封装在一个函数内),可以避免需要清理上个问题留下的数据的问题。
  • 变量命名与注释
    大模拟的题往往涉及很多相关的变量,变量命名应该尽量规范且贴合题意。退一步来说,最起码也得在变量定义处写好注释。

2. 代码

  • 当前这个代码得分40。初始化能运行的部件,不断更新可以运行的部件,运行到最后如果发现还有部件未运行或者不能运行,则说明有环路。
  • 满分ac的在这儿:点亮数字人生(原创代码100分)
#include"stdio.h"
#include"iostream"
#include"string"
using namespace std;
struct IN{
	int in;
	int num;
	int sp;
};
struct F{
	int fg;	//func
	int k;	//输入个数 
	IN in[5];
	int out;
	int ready;
};
int Q;
int M,N;
int  S;
int Not(int a){
	return 1-a;
}
int  And(F f){
	int t=f.in[0].sp;
	int k=f.k;
	for(int i=1;i<k;i++){
		t=t&f.in[i].sp;
	}
	return t;
}
int  Or(F f){
	int t=f.in[0].sp;
	int k=f.k;
	for(int i=1;i<k;i++){
		t=t|f.in[i].sp;
	}
	return t;
}
int  Xor(F f){
	int t=f.in[0].sp;
	int k=f.k;
	for(int i=1;i<k;i++){
		if(t!=f.in[i].sp){
			t=1;
		}
		else{
			t=0;
		}
	}
	return t;
}
int  Nand(F f){
	return 1-And(f);
}
int  Nor(F f){
	return 1-Or(f);
}
int find(char s[5]){
	if(s[0]=='A'){
		return 2;
	}
	else{
		if(s[0]=='O'){
			return 3;
		}
		else{
			if(s[0]=='X'){
				return 4;
			}
			else{
				if(s[1]=='A'){
					return 5;
				}
				else{
					if(s[2]=='T'){
						return 1;
					}
					else return 6;
				}
			}
		}
	}
	return 0;
}
int getnum(char s[10]){
	int i=1,num=0;
	while(s[i]!=0){
		num=num*10+s[i]-'0';
		i++;
	}
	return num;
}
int work(F *f){
	int fla[501];
	for(int i=1;i<=N;i++){
		fla[i]=0;
	}
	int flag=1,count2,count1=0,fff=0;
	while(flag){
		count2=count1;
		count1=0;
		flag=0;
		for(int i=1;i<=N;i++){
			if(f[i].ready==f[i].k&&fla[i]==0){
				int fg=f[i].fg;
				switch (fg){
					case 1:f[i].out=Not(f[i].in[0].sp);break;
					case 2:f[i].out=And(f[i]);break;
					case 3:f[i].out=Or(f[i]);break;
					case 4:f[i].out=Xor(f[i]);break;
					case 5:f[i].out=Nand(f[i]);break;
					case 6:f[i].out=Nor(f[i]);break;
					default:break;
				}
				fla[i]=1;
				for(int ii=1;ii<=N;ii++){
					for(int iii=0;iii<f[ii].k;iii++){
						if(f[ii].in[iii].in==0&&f[ii].in[iii].num==i){
							f[ii].in[iii].sp=f[i].out;
							f[ii].ready++;
						}
					}
				} 
			}
		}
		for(int i=1;i<=N;i++){
			if(fla[i]==0){
				flag=1;
				count1++;
			} 
		} 
		if(count2==count1&&count1!=0){
			fff=1;
			flag=0;
		}
	} 
	if(fff){
		return 1;
	}
	return 0;
}
int main(){
	int in[500][100];
	int out[500][100];
	int si[100];
	scanf("%d",&Q);
	for(int i=0;i<Q;i++){
		F f[501];
		scanf("%d%d",&M,&N);
		for(int j=1;j<=N;j++){
			char s[5];
			int k;
			scanf("%s%d",s,&k);
			f[j].k=k;
			f[j].fg=find(s);
			for(int l=0;l<k;l++){
				char L[10];
				scanf("%s",L);
				if(L[0]=='I'){
					f[j].in[l].in=1;
				}
				else{
					f[j].in[l].in=0;
				}
				f[j].in[l].num=getnum(L);
			}
		}
		scanf("%d",&S);
		for(int i1=0;i1<S;i1++){
			for(int j=1;j<=M;j++){
				scanf("%d",&in[i1][j]);
			}
		}
		for(int i1=0;i1<S;i1++){
			scanf("%d",&si[i1]);
			for(int j=0;j<si[i1];j++){
				scanf("%d",&out[i1][j]);
			}
		}
		int w=0;
		for(int i=0;i<S;i++){
			for(int ii=1;ii<=N;ii++){
				f[ii].ready=0;
			}
			for(int j=1;j<=M;j++){
				for(int ii=1;ii<=N;ii++){
					for(int jj=0;jj<f[ii].k;jj++){
						if(f[ii].in[jj].in==1&&f[ii].in[jj].num==j){
							f[ii].in[jj].sp=in[i][j];
							f[ii].ready++;
						}
					}
				}
			}
			w=work(f);
			if(w==1){
				printf("LOOP\n");
				break;
			} 
			else{
				for(int j=0;j<si[i];j++){
					printf("%d ",f[out[i][j]].out);
				}
				printf("\n");
			}
		} 
	}
	return 0;
}


/*
2
2 6
NOR 2 O4 I2
AND 2 O4 O6
XOR 2 O5 O1
NOT 1 O6
NAND 2 O2 O2
AND 2 I1 O3
2
0 0
1 0
3 2 3 4
6 1 2 3 4 5 6
3 5
XOR 2 I1 I2
XOR 2 O1 I3
AND 2 O1 I3
AND 2 I1 I2
OR 2 O3 O4
4
0 1 1
1 0 1
1 1 1
0 0 0
2 5 2
2 5 2
2 5 2
2 5 2

*/




Logo

电影级数字人,免显卡端渲染SDK,十行代码即可调用,工业级demo免费开源下载!

更多推荐