这个枚举题也卡时间?

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

时间: 2024-10-15 02:03:22

这个枚举题也卡时间?的相关文章

HDU1845 Jimmy’s Assignment(最大匹配)卡时间

Jimmy's Assignment Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1093    Accepted Submission(s): 446 Problem Description Jimmy is studying Advanced Graph Algorithms at his university. His mos

偶然看到的面试算法题_最短时间找出十包粉末中的两蓝粉末。

题目:有4个杯子,10包粉末,其中有2包溶于水变蓝,其余无色,粉末溶于水2min才能显现颜色.求找出两包蓝色粉末的最短时间.假设水和粉末用不完. 解:以下给出四种解法,标记10包粉末为(1,2 ... ) 杯子为[1,2,3,4]首先我想会不会是有某种算法,dp 二分..@[email protected]..没有,懵懵的. 法一:这是我最初想到的比较傻的方法 第一趟:[12,34,56,78] 每个杯子分别放两包加水融化,剩下两包不管.可能的情况: (1)0个杯子变色,说明剩下两包就是蓝粉末

!HDU 4311 最小曼哈顿距离-思维&amp;卡时间-(横纵坐标分开算,排序)

题意:有n个点,求以这n个点中的某一点为起点,到各点的曼哈顿距离和最小是多少 分析: 暴力枚举又要超时,这种题一般都是考思维了,多半都是用技巧找到一个高效的方法.个人觉得这题跟上一篇文章的题是一个类型.这种思想要记住. 这题也是用"分治",虽说题目要求的是曼哈顿距离,但是我们为什么真的就要一步到位的求呢,可以横纵坐标分开求,先x排序,然后遍历一遍,求出横坐标的距离,然后y排序,遍历一遍求出坐标的距离加在刚才求得的x的距离上,就是曼哈顿距离了. 这里有一个非常巧妙但是其实很显而易见的东西

hdu 3572 Task Schedule 最大流 Dinic算法,,卡时间。。建图非常有讲究

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4617    Accepted Submission(s): 1513 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

Lunch Time(费用流变型题,以时间为费用)

Lunch Time http://acm.hdu.edu.cn/showproblem.php?pid=4807 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 782    Accepted Submission(s): 183 Problem Description The campus of Nanjing University

每天一套题打卡|河南省第七届ACM/ICPC

A 海岛争霸 题目:Q次询问,他想知道从岛屿A 到岛屿B 有没有行驶航线,若有的话,所经过的航线,危险程度最小可能是多少. 多源点最短路,用floyd 在松弛更新:g[i][k] < g[i][j] && g[k][j] < g[i][j]时,g[i][j] = max(g[i][k],g[k][j]); #include<bits/stdc++.h> using namespace std; const int maxn = 510; int n,m; int q

April Fools Contest 2017 题解&amp;源码(A,数学 B,数学 C,数学 D,字符串 E,数字逻辑 F,排序,卡时间)

A. Numbers Joke time limit per test:2 seconds memory limit per test:64 megabytes input:standard input output:standard output Input The input contains a single integer a (1 ≤ a ≤ 30). Output Output a single integer. Example Input 3 Output 27 题目链接:http

HDU 4343 多查询求区间内的最大不相交区间个数-思维&amp;贪心-卡时间&amp;二分&amp;剪枝

题意:给你一些区间,现在有m个查询,求出每个查询的区间内的最大的不相交区间个数 分析: 几天前那道说谎问题时用dp的摞箱子模型求的最大的不相交区间个数,但是这题不能用这个方法,因为这题是动态的查询,不可能每个查询dp一次,超时. 这题用贪心策略.求区间[l~r]里的最大不相交区间,贪心策略就应该先选该区间内右端点最小的,这样给以后待选的区间留下更大的空间,所以我们的做法就是先按照区间的右端点排序,然后每次查询依次挑出查询区间里右端点最小的,并且把查询区间的左端点更新为刚才挑出的区间的右端点(这个

!HDU 4334 集合各出一数和为0是否存在-思维、卡时间-(指针的妙用)

题意:有5个集合,集合的大小是n,每一个集合出一个数,问能不能找到五个数的和为0.数据范围:T<=50:n<=200 分析: 暴力枚举是n^5*T,超时,那么就要用一些技巧了. 这里有一个指针的妙用:如何在O(n)的复杂度找A,B,使得A+B==C(A,B分别属于一个数列a,b).做法是先把a,b分别按升序排序,然后一个指针i指向a的首,指针j指向b的尾,判定指针指向的数的和是否==C,若等于则结束查找,若小于,则i++,若大于则 j- -,如果有一个指针已经走到了头还没找到A+B==C,则说