这个枚举题也卡时间?

Posted kstranger

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这个枚举题也卡时间?相关的知识,希望对你有一定的参考价值。

题目: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
";

        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
";

        return;

    }

    if(ans2==2)

    {

        cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output inverted
";

        return;

    }

    if(ans2==0)

    {

        cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output stuck at 0
";

        return;

    }

    if(ans2==1)

    {

        cout<<"Case "<<t<<": Gate "<<ans1<<" is failing; output stuck at 1
";

        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;

}

 

 
 
 

以上是关于这个枚举题也卡时间?的主要内容,如果未能解决你的问题,请参考以下文章

PAT1049-----枚举法,找规律题,注意降低时间复杂度

[kuangbin带你飞]专题二十二 区间DP----POJ - 2955

Java中枚举的写法和用法

[LeetCode] 1074. 元素和为目标值的子矩阵数量

P2216 [HAOI2007]理想的正方形 - 单调队列

为啥这个代码片段说包含错误?