题目:My Bad
时间限制:1.0s 内存限制:256.0MB
问题描述
一个逻辑电路将其输入通过不同的门映射到输出,在电路中没有回路。输入和输出是一个逻辑值的有序集合,逻辑值被表示为1和0。我们所考虑的电路由与门(and gate,只有在两个输入都是1的时候,输出才为1)、或门(or gate,只要两个输入中有一个是1,输出就是1)、异或门(exclusive or(xor)gate,在两个输入中仅有一个是1,输出才是1)和非门(not gate,单值输入,输出是输入的补)组成。下图给出两个电路。
不幸的是,在实际中,门有时会出故障。虽然故障会以多种不同的方式发生,但本题将门会出现的故障限于如下三种形式之一:
1)总是与正确的输出相反;
2)总是产生0;
3)总是产生1;
在本题给出的电路中,最多只有一个门出故障。
请编写一个程序,对一个电路进行分析,对多组输入和输出进行实验,看电路运行是正确的还是不正确的。如果至少有一组输入产生了错误的输出,程序要确定唯一的出故障的门,以及这个门出故障的方式。但这也可能是无法判断的。
输入格式
输入由多组测试数据组成,每组测试用例描述了一个电路及其输入和输出。每个测试数据按序给出下述部分。
1. 一行给出3个正整数:在电路中输入的数量(N ≤ 8),门的数量(G ≤ 19)和输出的数量(U ≤ 19)。
2. 每行一个门,第一行描述g1门,如果有若干个门,则下一行描述g2门,以此类推。每行给出门类型(a = and,n = not,o = or,x = exclusive or)和对这个门的所有输入的标识符,对这个门的输入来自电路输入(i1, i2, …)或来自另一个门的输出(g1, g2, …)。
3. 一行给出与U个输出u1, u2, ….所关联的门的编号。例如,如果有三个输出,u1来自g5,u2来自g1,u3来自g4,那么这一行为:5 1 4。
4. 一行给出一个整数,表示对电路的进行实验的次数(B)。
5. 最后给出B行,每行(N+U)个值(1和0),给出实验的输入值和相应的输出值。不存在有两个相同输入的情况。
输入中的标识符或数字以空格分开,输入以包含3个0的一行结束。
输出格式
对于输入数据中的每个电路,输出测试数据的编号(从1开始),然后输出一个冒号和一个空格,再输出电路分析,内容为如下之一(用#代替相应的门的编号):
No faults detected
Gate # is failing; output inverted
Gate # is failing; output stuck at 0
Gate # is failing; output stuck at 1
Unable to totally classify the failure
在图1和图2 中给出的电路图是第一个和最后一个测试数据。
样例输入
2 2 1
o i1 i2
n g1
2
2
1 0 0
0 0 1
2 1 1
a i1 i2
1
1
1 0 1
2 1 1
a i1 i2
1
2
1 0 1
1 1 1
1 1 1
n i1
1
2
1 1
0 0
3 4 4
n g4
a i1 i2
o i2 i3
x i3 i1
2 3 4 1
4
0 1 0 0 1 0 1
0 1 1 0 1 1 0
1 1 1 0 1 0 1
0 0 0 0 0 0 1
0 0 0
样例输出
Case 1: No faults detected
Case 2: Unable to totally classify the failure
Case 3: Gate 1 is failing; output stuck at 1
Case 4: Gate 1 is failing; output inverted
Case 5: Gate 2 is failing; output stuck at 0
数据规模和约定
N<=8;G,U<=19
思路很简单:就是枚举所有情况(枚举每个门的所有情况看当前枚举的情况是不是可以,如果有多个情况都可以就输出Unable to totally classify the failure,如果所有门都能正常过样例就输出No faults detected,其他情况单独处理。具体见以下代码)
code1:(蒟蒻的代码)(为什么用数组存边就tle了qaq)
#include <iostream> #include <string> #include <cstring> #include <queue> using namespace std; const int N = 20; int n,g,u; int b; int input[100][2*N],output_from[N],door[N+10][N+10],cnt[N],temcnt[N];//第一维的1到n个表示来自于哪个输入,n+1到n+g+1个表示来自于哪个门 char door_class[N]; bool check(int keys[],int bad_door,int cas){//check用来检查坏的门的cas情况 memcpy(temcnt,cnt,sizeof cnt); bool ok=true; int f[n+g+10]; int hh=1,tt=n; int q[2*N]; //memset (f,0,sizeof f); for(int i=1;i<=g;i++){ if(door_class[i]==‘a‘){ f[i+n]=1; } else f[i+n]=0; } for(int i=1;i<=n;i++){ // cout<<keys[i]<<" "; f[i]=keys[i]; q[i]=i; } while(hh<=tt){ int t = q[hh++]; // cout<<t<<endl; // cout<<t<<endl; if(t==bad_door){ if(cas==2){ f[t]=!f[t]; } else f[t]=cas; } for(int i=1;i<=g;i++){ // cout<<door[t][i]<<endl; if(door[t][i]){ cnt[i]--; // cout<<door_class[i]<<endl; if(door_class[i]==‘a‘){ if(f[t]==0){ f[i+n]=0; } } else if(door_class[i]==‘o‘){ if(f[t]==1){ f[i+n]=1; } } else if(door_class[i]==‘x‘){ f[i+n]=f[i+n]^f[t]; } else f[i+n]=!f[t]; if(cnt[i]==0){ //q.push(i+n); q[++tt]=i+n; } } } } memcpy(cnt,temcnt,sizeof cnt); for(int i=1;i<=u;i++){ if(f[output_from[i]+n]!=keys[i+n]){ return false; } } return true; } void work(int t){ bool ok=true; for(int i=1;i<=b;i++){ if(!check(input[i],-100,-1)){ ok=false; break; } } // cout<<ok<<endl; if(ok){ cout<<"Case "<<t<<": No faults detected"<<endl; } else{ int bad_num=0; int bad_door=-1; int bad_case=-1; int i,j,k; for(j=1;j<=g;j++){ for(k=0;k<=2;k++){ ok=true; for(i=1;i<=b;i++){ if(!check(input[i],j+n,k)){ ok=false; break; } } if(ok) { bad_door=j; bad_case=k; bad_num++; } } } // cout<<bad_case<<" "<<bad_door<<endl; if(bad_num>1){ cout<<"Case "<<t<<": Unable to totally classify the failure"<<endl; } else if(bad_case==2){ cout<<"Case "<<t<<": Gate "<<bad_door<<" is failing; output inverted"<<endl; } else if(bad_case==1){ cout<<"Case "<<t<<": Gate "<<bad_door<<" is failing; output stuck at 1"<<endl; } else { cout<<"Case "<<t<<": Gate "<<bad_door<<" is failing; output stuck at 0"<<endl; } } } int main(){ ios::sync_with_stdio(false); int t=1; while(cin>>n>>g>>u&&n){ memset(door,0,sizeof door); //memset (output_from,0,sizeof output_from); memset (cnt,0,sizeof cnt); for(int i=1;i<=g;i++){ char c; cin>>c; door_class[i]=c; if(c==‘o‘||c==‘a‘||c==‘x‘){ string s1,s2; cin>>s1>>s2; // cout<<s1<<s2<<endl; int num1=0,num2=0; for(int j=1;j<s1.length();j++){ num1=num1*10; num1+=s1[j]-‘0‘; } for(int j=1;j<s2.length();j++){ num2=num2*10; num2+=s2[j]-‘0‘; } if(s1[0]==‘i‘)door[num1][i]=1; else door[num1+n][i]=1; if(s2[0]==‘i‘)door[num2][i]=1; else door[num2+n][i]=1; cnt[i]+=2; // cout<<cnt[i]<<endl; } else{ string s1; cin>>s1; int num=0; for(int j=1;j<s1.length();j++){ num=num*10; num+=s1[j]-‘0‘; } if(s1[0]==‘i‘)door[num][i]=1; else door[num+n][i]=1; cnt[i]++; } } for(int i=1;i<=u;i++){ int ui; cin>>ui; output_from[i]=ui; } cin>>b; for(int i=1;i<=b;i++){ for(int j=1;j<=n+u;j++){ int tem; cin>>tem; input[i][j]=tem; } } work(t); t++; } }
code2:(ac的代码)大佬用前向星就ac tql 详细给出注释
#include<iostream> #include<string> #include<string.h> #include<stdlib.h> using namespace std; struct dat_edge { int aim,last; }edge[201]; int n,m,k,inde[101],coun[101],tmp_coun[101],pl[101],len_edge,num_key,key[300][101]; char kind[101];//kind保存门的种类 void insert_edge(int x,int y)//从x到y有一个边比如i0=>m1(这里是前向星) { len_edge++; edge[len_edge].aim=y; edge[len_edge].last=pl[x]; pl[x]=len_edge; } void init(int o,string z)//o表示在处理第几个门 { int p,i,num; string t; p=1; z+=‘ ‘;//为了以后处理方便 for(i=1;i<z.length();i++)//例如z=" i1 i2 " if(z[i]==‘ ‘) { t=z.substr(p,i-p);//取一个来源 if(t[0]==‘i‘)//来自于输入 num=0; else num=n; if(t.length()==2) num+=t[1]-‘0‘;//来自于第几个门或者输入 else { num+=(t[1]-‘0‘)*10+t[2]-‘0‘;//处理10以上的标签 } coun[o]++;//记录o这个门的输入个数 insert_edge(num,o);//输入的编号从1到n,门的编号从n到n+m,输出编号n+m到n+m+k p=i+1; } } bool solve(int key[],int poi,int sta)//key表示第i组输入和输出,poi表示,sta表示所属情况 { int i,p,o,w,tmp,que[101],f[101]; for(i=1;i<=n+m+k;i++) { f[i]=0;//f数组保存每个节点的状态要么是1要么是0 } for(i=1;i<=n;i++) f[i]=key[i]; for(i=1;i<=m;i++) { if(kind[i]==‘a‘)//如果当前门是与门 f[i+n]=1; else f[i+n]=0; } o=n;w=0;//w表示对头,o表示队尾 for(i=1;i<=n;i++) que[i]=i;//先把所有输入都入队 while(w<o) { w++; if(que[w]==poi)//如果当前处理到第poi个门 { if(sta==2) f[que[w]]=!f[que[w]];//第二个状态就翻转 else f[que[w]]=sta;//第0个状态就取0,第三个状态就取1 } p=pl[que[w]]; while(p!=-1)//遍历每一个出边 { coun[edge[p].aim]--;//指向的顶点的入度减一 if(coun[edge[p].aim]==0) { que[++o]=edge[p].aim;//如果指向的顶点计算完了就把它入队 } tmp=edge[p].aim; if(kind[tmp-n]==‘a‘)//出边必然指向门 { if(f[que[w]]==0) f[tmp]=0; } else if(kind[tmp-n]==‘o‘) { if(f[que[w]]==1) f[tmp]=1; } else if(kind[tmp-n]==‘x‘) { f[tmp]=f[tmp]^f[que[w]]; } else { f[tmp]=!f[que[w]]; } p=edge[p].last; } } for(i=1;i<=n+m+k;i++) coun[i]=tmp_coun[i]; for(i=1;i<=k;i++) { if(f[inde[i]+n]!=key[n+i]) return false; } return true; } void work(int t) { int i,j,p,ans1,ans2,coun_ans; bool ok=true; for(i=1;i<=num_key;i++)//遍历每一次询问 { if(!solve(key[i],-1,-1))//bfs判断方案的可行性 { ok=false; break; } } if(ok) { cout<<"Case "<<t<<": No faults detected\n"; return; } ans1=ans2=coun_ans=0; for(i=1;i<=m;i++)//枚举每个门 { for(j=0;j<=2;j++)//枚举三种情况 { ok=true; for(p=1;p<=num_key;p++)//枚举每一种给出的情况 { ok=solve(key[p],i+n,j);//枚举第i个门第j种情况 if(!ok) break; } if(ok)//如果第i个门出现了第j个情况并且当前样例在这个情况下合理 { ans1=i;//ans1表示第几个门 ans2=j;//ans2表示第几种情况 coun_ans++;//count_ans>1表示情况有多种就没有办法确定 } } } if(coun_ans!=1) { cout<<"Case "<<t<<": Unable to totally classify the failure\n"; return; } if(ans2==2) { cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output inverted\n"; return; } if(ans2==0) { cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output stuck at 0\n"; return; } if(ans2==1) { cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output stuck at 1\n"; return; } } int main() { int t,i,j; string z; t=0;//t 用来记录第几组测试数据 while(cin>>n>>m>>k && n+m+k!=0)//n m k 分别代表输入数量,门的数量和输出数量 { t++; memset(coun,0,sizeof(coun));//coun 表示每个顶点的输入个数 len_edge=-1;//len_edge表示边的个数(把每一对输入输出抽象为一个边)把问题抽象为一个图,把每个门包括输入输出点都抽象为顶点 for(i=1;i<=n+m+k;i++) pl[i]=-1;//pl保存该顶点的出边 for(i=1;i<=m;i++)//输入m个门以及它的数据来源 { cin>>kind[i];//kind保存该门的种类 getline(cin,z); init(i+n,z);//可以初始化为一个图 } for(i=1;i<=n+m+k;i++) tmp_coun[i]=coun[i];//临时保存一下每个顶点的输入个数 for(i=1;i<=k;i++) cin>>inde[i];//输出来自于哪个门 cin>>num_key;//判别条件的个数 for(i=1;i<=num_key;i++) for(j=1;j<=n+k;j++) cin>>key[i][j];//第i个询问的记录 work(t); } return 0; }
原文地址:https://www.cnblogs.com/kstranger/p/12242442.html