zoukankan      html  css  js  c++  java
  • NOIP2003 侦探推理 详解

    题目描述

    明明同学最近迷上了侦探漫画《柯南》并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏。游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明明的任务就是找出这个罪犯。接着,明明逐个询问每一个同学,被询问者可能会说:

    证词中出现的其他话,都不列入逻辑推理的内容。

    明明所知道的是,他的同学中有N个人始终说假话,其余的人始终说真。

    现在,明明需要你帮助他从他同学的话中推断出谁是真正的凶手,请记住,凶手只有一个!

    输入输出格式

    输入格式:

    输入由若干行组成,第一行有二个整数,M(1≤M≤20)、N(1≤N≤M)和P(1≤P≤100);M是参加游戏的明明的同学数,N是其中始终说谎的人数,P是证言的总数。接下来M行,

    每行是明明的一个同学的名字(英文字母组成,没有主格,全部大写)。

    往后有P行,每行开始是某个同学的名宇,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式。证词每行不会超过250个字符。

    输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。

    输出格式:

    如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是罪犯,则输出 Cannot Determine;如果程序判断出没有人可能成为罪犯,则输出 Impossible。

    输入输出样例

    输入样例#1:
    3 1 5
    MIKE
    CHARLES
    KATE
    MIKE: I am guilty.
    MIKE: Today is Sunday.
    CHARLES: MIKE is guilty.
    KATE: I am guilty.
    KATE: How are you??
    
    输出样例#1:
    MIKE

    这题就是个坑←_←,这数据就是个逗比→_→ 
    
    用suspect[i,j]记录i对j是不是凶手的判断:
    suspect[i,j]=1时,i认为j是凶手;
    suspect[i,j]=-1时,i认为j不是凶手;
    
    peo[i]记录第i个人的名字
    用a[i].day记录第i个人认为今天是星期几
    
    然后咱枚举犯人(guilty)和星期几(today)来对每个人逐一判断(不会傻到用组合去判断谁说假话吧0.0):
    咱们用f数组记录我们对第i个人的判断
    如果f[i]=1说明他说真话,f[i]=2说明他说假话(注意清0)
    
    由于全部人分为三类:只说真话,只说假话,说废话
    所以如果有人既说过真话又说过假话这种情况是不会存在的,直接判断出false就行
    
    然后分类讨论:
    1、suspect[i,guilty]=1
    说明i说真话,如果f[i]=2即对于这组guilty、today他说过假话,矛盾,返回false 不然的话他说真话f[i]=1
    2、suspect[i,guilty]=2
    说明i说假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=2
    3、对于i对除了guilty以外所有人(j<>guilty)的判断
    (1)如果suspect[i,j]=1 说明他认为j是凶手,是假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=22)如果suspect[i,j]=-1说明他认为j不是凶手,是真话,如果f[i]=2即他说过假话,矛盾返回false 不然的f[i]=1
    4、a[i].day>0即他说过今天是星期几并且a[i].j<>today 即他说错了,是假话,如果f[i]=1即他说过真话,矛盾返回false,不然f[i]=2
    判断完毕=w=
    
    然后我们统计f[i]=2即说谎的人数t1和f[i]=0即不确定的人数t2
    然后关键来了
    究竟什么是满足要求的情况呢?
    t1不一定非要严格等于说谎人数m,
    因为有人不确定,
    而这批不确定的人中可能也有人是说谎者只是他没说有用的而已(这里一开始没想到跪了3个小时QAQ)
    【我走的最长的路就是你的套路】
    所以满足的条件是 (t1<=m)and  (t1+t2>=m)
    
    由于结果有三种情况:
    1、真相只有一个——有且只有1个满足条件的犯人,直接输出名字
    2、他们同伙作案——有大于1个人满足他是犯人的条件,输出Cannot Determine
    3、错误的嫌疑人——没有人满足犯人的条件,输出 Impossible 
    
    所以我们如果判断出一个人是犯人不要着急输出,
    而是记录我们找到的满足犯人条件的人数t,以及他的名字ans,
    每找到一个就t+1,ans更新为他的名字
    
    一个小细节就是我们是犯人和星期同时枚举的,
    所以如果我们判断出一个人是犯人就可以直接去判断下一个人不然这一个人会加好几遍
    
    还有判断的时候是区分大小写的,
    第一组数据中叫GUILTY的那个人说:I am GUILTY 真的是句废话,他就是说他叫GUILTY(=。=)
    AC代码:
     1 #include<cstdio>
     2 #include<map>
     3 #include<iostream>
     4 #include<string>
     5 using namespace std;
     6 int n,m,p,s[22][102],l[22],d[22][102],day[22][102],gu[22];
     7 map<string,int>t;
     8 map<int,string>h;
     9 string u,v[102],g[102],q[102],bb;
    10 int main()
    11 {
    12     scanf("%d%d%d",&m,&n,&p);
    13     for(int i=0;i<m;i++)
    14     {
    15         cin>>u;
    16         t[u]=i+1;
    17         h[i+1]=u;
    18     }
    19     for (int i=0;i<p;i++)
    20     {
    21         int y,ll=1;u="";
    22         while(u[ll-1]!='.'&&u[ll-1]!='?'&&u[ll-1]!='!') 
    23         {
    24             cin>>bb;
    25             if(ll>1)u+=' ';
    26             u+=bb;
    27             ll=u.length();
    28         }
    29         for(int j=0;j<ll&&u[j]!=':';j++) 
    30         {
    31             v[i]+=u[j];
    32             y=j;
    33         }
    34         int jj=t[v[i]],b=-1,nn=0,uu=0;
    35         for(int j=y+3;j<ll;j++)
    36         {
    37             if(!uu) g[i]+=u[j];else q[i]+=u[j];
    38             if(!nn&&!uu&&u[j+1]==' ')for(int k=1;k<=m;k++)if(h[k]==g[i]){b=k;break;}
    39             if(b!=-1&&!nn&&!uu){g[i]=u[j+2];j+=2;nn=1;}
    40             if(g[i]=="Today is ")uu=1;
    41         }
    42         if(g[i]=="I am guilty.")s[jj][l[jj]++]=1;
    43         if(g[i]=="I am not guilty.")s[jj][l[jj]++]=2;
    44         if(g[i]=="is guilty."){s[jj][l[jj]]=3;d[jj][l[jj]++]=b;}
    45         if(g[i]=="is not guilty."){s[jj][l[jj]]=4;d[jj][l[jj]++]=b;}
    46         if(g[i]=="Today is ")
    47         {
    48             s[jj][l[jj]]=5;
    49             if(q[i]=="Monday.")day[jj][l[jj]++]=1;
    50             if(q[i]=="Tuesday.")day[jj][l[jj]++]=2;
    51             if(q[i]=="Wednesday.")day[jj][l[jj]++]=3;
    52             if(q[i]=="Thursday.")day[jj][l[jj]++]=4;
    53             if(q[i]=="Friday.")day[jj][l[jj]++]=5;
    54             if(q[i]=="Saturday.")day[jj][l[jj]++]=6;
    55             if(q[i]=="Sunday.")day[jj][l[jj]++]=7;
    56         }
    57     }
    58     for(int i=1;i<=m;i++)
    59     for(int j=1;j<=7;j++)
    60     {
    61         int fa=0,T,F,abc=0;
    62         for(int k=1;k<=m;k++)
    63         {
    64             T=F=0;
    65             for(int kk=0;kk<l[k];kk++)
    66             {
    67                 if(s[k][kk]==1)if(i==k)T=1;else F=1;
    68                 if(s[k][kk]==2)if(i!=k)T=1;else F=1;
    69                 if(s[k][kk]==3)if(i==d[k][kk])T=1;else F=1;
    70                 if(s[k][kk]==4)if(i!=d[k][kk])T=1;else F=1;
    71                 if(s[k][kk]==5)if(j==day[k][kk])T=1;else F=1;
    72             }
    73             if(T&&F)break;
    74             if(F)fa++;
    75             if(!T&&!F)abc++;
    76         }
    77         if(T&&F)continue;
    78         if(fa==n||fa<=n&&fa+abc>=n)gu[i]=1;
    79     }
    80     int ans=0;
    81     for(int i=1;i<=m;i++)if(gu[i])ans++;
    82     if(!ans)printf("Impossible");
    83     else if(ans>1)printf("Cannot Determine");
    84     else for(int i=1;i<=m;i++)if(gu[i]){cout<<h[i];break;}
    85     return 0;
    86 }
    代码


    作者:乌鸦坐飞机
    出处:http://www.cnblogs.com/whistle13326/
    新的风暴已经出现 怎么能够停止不前 穿越时空 竭尽全力 我会来到你身边 微笑面对危险 梦想成真不会遥远 鼓起勇气 坚定向前 奇迹一定会出现

     
  • 相关阅读:
    算法
    jquery-lazyload延迟加载图片
    配置图片服务器
    Flutter开发之dart语言从入门到精通(从入坑到入土)
    阿里淘系技术分享:Flutter 快速上手方法!!!
    如何优雅的处理 Android 重复点击 [建议收藏]
    还谈论Android的前景?根本没什么好问的……
    一个商业级智能家居 Android 开源项目分享
    【前端算法】拼多多技术面试算法题分享
    美团Android岗面试真题:手写红黑树详解
  • 原文地址:https://www.cnblogs.com/whistle13326/p/6648567.html
Copyright © 2011-2022 走看看