侦探推理

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制

  1. 3 1 5
  2. MIKE
  3. CHARLES
  4. KATE
  5. MIKE: I am guilty.
  6. MIKE: Today is Sunday.
  7. CHARLES: MIKE is guilty.
  8. KATE: I am guilty.
  9. KATE: How are you??
输出样例#1: 复制

  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]=2

(2)如果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

然后我们统计f[i]=2即说谎的人数t1和f[i]=0即不确定的人数t2

然后关键来了,究竟什么是满足要求的情况呢?

t1不一定非要严格等于说谎人数m,因为有人不确定,而这批不确定的人中可能也有人是说谎者只是他没说有用的而已。所以满足的条件是 (t1<=m)and  (t1+t2>=m)

由于结果有三种情况:

1、真相只有一个——有且只有1个满足条件的犯人,直接输出名字

2、他们同伙作案——有大于1个人满足他是犯人的条件,输出Cannot Determine

3、错误的嫌疑人——没有人满足犯人的条件,输出 Impossible

所以我们如果判断出一个人是犯人不要着急输出,

而是记录我们找到的满足犯人条件的人数t,以及他的名字ans,

每找到一个就t+1,ans更新为他的名字

一个小细节就是我们是犯人和星期同时枚举的,所以如果我们判断出一个人是犯人就可以直接去判断下一个人不然这一个人会加好几遍。还有判断的时候是区分大小写的。

  1. #include<cstdio>
  2. #include<map>
  3. #include<iostream>
  4. #include<string>
  5. using namespace std;
  6. int n,m,p;
  7. /*用suspect[i,j]记录i对j是不是凶手的判断:
  8. suspect[i,j]=1时,i认为j是凶手;
  9. suspect[i,j]=-1时,i认为j不是凶手;*/
  10. int s[][];
  11. int l[];
  12. int d[][];
  13. int day[][];
  14. int gu[];
  15. map<string,int>t;//用来记名字用
  16. map<int,string>h;
  17. string u,v[],g[],q[],bb;
  18. int main()
  19. {
  20. cin>>m>>n>>p;
  21. for(int i=;i<=m;i++)
  22. {
  23. cin>>u;
  24. t[u]=i;
  25. h[i]=u;
  26. }
  27. for(int i=;i<=p;i++)
  28. {
  29. //cout<<"i "<<i<<endl;
  30. int y,ll=;
  31. u="";
  32.  
  33. //一个个单词读进来,遇到.?!表示语句结束
  34. while(u[ll-]!='.'&&u[ll-]!='?'&&u[ll-]!='!')
  35. {
  36. cin>>bb;
  37. //cout<<"bb "<<bb<<endl;
  38. if(ll>) u+=' ';
  39. u+=bb;
  40. ll=u.length(); //ll表示整一句的字母数
  41. }
  42. //cout<<"u "<<u<<endl;
  43. //cout<<"ll "<<ll<<endl;
  44. //把证词人名整理好放进v数组里
  45. for(int j=;j<ll&&u[j]!=':';j++)
  46. {
  47. v[i]+=u[j];
  48. y=j;
  49. }
  50. int jj=t[v[i]];//这句话是编号为jj的人说的
  51. int b=-,nn=,uu=;
  52. //b表示第一个单词是人名的话,存放这是第几个人
  53. //y用来标记人名到底几个字符位置
  54. //uu表示输入的句子是不是关于Today is的
  55. //g用于把句子拼接起来
  56. for(int j=y+;j<ll;j++)
  57. {
  58. //如果是关于星期的,就把星期几放到q里
  59. if(!uu) g[i]+=u[j];else q[i]+=u[j];
  60. //查一查此时的g[i]是不是某个人的名字,MIKE is guilty.
  61. //是的话吧第几个人k放到b里,h[k]返回第k个人名字符串
  62. if(!nn&&!uu&&u[j+]==' ')for(int k=;k<=m;k++)if(h[k]==g[i]){b=k;break;}
  63. //第一个单词是人名
  64. if(b!=-&&!nn&&!uu){g[i]=u[j+];j+=;nn=;}
  65. if(g[i]=="Today is ")uu=;
  66. }
  67. //l[jj]表示第jj个人的第几个观点
  68. //s[jj][l[jj]]=3,d[jj][l[jj]++]=b表示第jj个人的第 l[jj]++个观点认为b是凶手
  69. if(g[i]=="I am guilty.")s[jj][l[jj]++]=;
  70. if(g[i]=="I am not guilty.")s[jj][l[jj]++]=;
  71. if(g[i]=="is guilty."){s[jj][l[jj]]=;d[jj][l[jj]++]=b;}
  72. if(g[i]=="is not guilty."){s[jj][l[jj]]=;d[jj][l[jj]++]=b;}
  73. if(g[i]=="Today is ")
  74. {
  75. //s[jj][l[jj]]=5,day[jj][l[jj]++]=1表示第jj个人的第 l[jj]++个观点认为今天是星期一
  76. s[jj][l[jj]]=;
  77. if(q[i]=="Monday.")day[jj][l[jj]++]=;
  78. if(q[i]=="Tuesday.")day[jj][l[jj]++]=;
  79. if(q[i]=="Wednesday.")day[jj][l[jj]++]=;
  80. if(q[i]=="Thursday.")day[jj][l[jj]++]=;
  81. if(q[i]=="Friday.")day[jj][l[jj]++]=;
  82. if(q[i]=="Saturday.")day[jj][l[jj]++]=;
  83. if(q[i]=="Sunday.")day[jj][l[jj]++]=;
  84. }
  85. }
  86. //cout<<"输入完毕"<<endl;
  87. //最后遍历每个人假设他是凶手
  88. for(int i=;i<=m;i++)
  89. {
  90. //遍历今天星期几
  91. for(int j=;j<=;j++)
  92. {
  93. //针对每一个的证词判断他说真话还是假话
  94. //fa统计说谎话的人
  95. //abc统计不真不假的人
  96. int fa=,T,F,abc=;
  97. for(int k=;k<=m;k++)
  98. {
  99. T=F=;
  100. //l[k]表示第k个人说的证词条数(信息数)
  101. for(int kk=;kk<l[k];kk++)
  102. {
  103. //关于凶手
  104. if(s[k][kk]==)if(i==k)T=;else F=;
  105. if(s[k][kk]==)if(i!=k)T=;else F=;
  106. if(s[k][kk]==)if(i==d[k][kk])T=;else F=;
  107. if(s[k][kk]==)if(i!=d[k][kk])T=;else F=;
  108. //关于星期
  109. if(s[k][kk]==)if(j==day[k][kk])T=;else F=;
  110. }
  111. if(T&&F)break;
  112. if(F) fa++;
  113. if(!T&&!F)abc++;
  114. }
  115. if(T&&F)continue;
  116. //如果说谎话的人正好n个或<=n个 ,
  117. //且说谎话的人和不真不假的人比n个多
  118. //gu[i]=1表示第i个人是凶手成立
  119. if(fa==n||fa<=n&&fa+abc>=n)gu[i]=;
  120. }
  121. }
  122. //ans统计有多少人可能是凶手
  123. int ans=;
  124. for(int i=;i<=m;i++)if(gu[i])ans++;
  125. if(!ans)printf("Impossible");
  126. else if(ans>)printf("Cannot Determine");
  127. else for(int i=;i<=m;i++)if(gu[i]){cout<<h[i];break;}
  128. return ;
  129. }

---------------------
作者:WhiStLenA
来源:CSDN
原文:https://blog.csdn.net/whistlena/article/details/78240157

洛谷P1039 侦探推理(模拟)的更多相关文章

  1. 洛谷 P1039侦探推理

    /* 枚举罪犯和星期几,那么所有人说的话是真是假一目了然. 首先一个人不能既说真话又说假话. 即: I am guilty. I am not guilty. 因为非真即假,所以直接判断impossi ...

  2. [NOIP2003] 提高组 洛谷P1039 侦探推理

    题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明 ...

  3. 洛谷 P1039 侦探推理

    题目:https://www.luogu.org/problemnew/show/P1039 分析: 这道题是一道有技术含量的模拟,我们主要是不要让计算机向人一样思考,只需要让他穷举变化的星期几和当罪 ...

  4. 洛谷P1039侦探推理题解

    #include<cstdio> #include<cstring> #include<string> #include<iostream> using ...

  5. Luogu P1039 侦探推理(模拟+枚举)

    P1039 侦探推理 题意 题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯 ...

  6. 【洛谷P1039】侦探推理

    侦探推理 题目链接 这是一道恶心至极的模拟题 我们可以枚举罪犯是谁,今天是星期几,从而判断每个人说的话是真是假 若每个人说的话的真假一致,且说谎话的人数<=k且说真话的人数<=m-k,就是 ...

  7. 洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)

    洛谷P1667 数列 题目描述 给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的.现在你有一个操作可以改变数列,选择一个区间[X,Y]满足\(A_X +A_{ ...

  8. P1039 侦探推理(洛谷)

    昨天做了一个非常神奇的题,告诉我们做题之前一定要好好检测评测姬! 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先 ...

  9. LUOGU P1039 侦探推理 (字符串+模拟)

    传送门 解题思路 一道%你神题,\(string\)好强大啊..首先枚举一个周几,再枚举一个罪犯是谁,然后判断的时候就是枚举所有人说的话.定义\(fAKe[i]\)表示第\(i\)个人说的是真话还是假 ...

随机推荐

  1. 为什么想起开通blog?

    为什么想起开通博客 2016年跨年夜写年终总结时,曾对自己许下愿,要成为一个会讲“故事”的人,无奈口才不行,写字也不好看,所以只能在电脑上码码字代替了. 在我看来,这“故事”该有许多种含义:首先,电子 ...

  2. python—DAY1

    # user = "123"# possword = "111"# count = 0## while count < 3:# user_name = i ...

  3. BT详解

    bittorrent是一个文件分发协议,它使用url来定位文件而且跟web服务无缝集成.当有多个人同时下载同一个文件时,下载者之间可以互相上传自己已有的那部分文件,让一个文件支持很多人同时下载却只增加 ...

  4. 4--Postman--Request&Response

    //var josndata=JSON.parse(responseBody);//获取body中返回的所有参数//tests["code"]=josndata.code===20 ...

  5. vue+koa实现简单的图书小程序(2)

    记录一下实现我们图书的扫码功能: https://developers.weixin.qq.com/miniprogram/dev/api/scancode.html要多读文档 scanBook () ...

  6. sort()的用法,参数以及排序原理(转载)

    sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点.语法:arrayObject.sort(sortby):参数sortby可选.规定排序顺序.必须是函 ...

  7. Python第九课学习

    Python第九课学习 数据结构: 深浅拷贝 集合set 函数: 概念 创建 参数 return 定义域 www.cnblogs.com/yuanchenqi/articles/5782764.htm ...

  8. 固态硬盘Ghost安装Windows 10无法引导的问题

    机器配置如下: 电脑型号 技嘉 B360M POWER 台式电脑 操作系统 Windows 10 64位 ( DirectX 12 ) 处理器 英特尔 Core i7-8700 @ 3.20GHz 六 ...

  9. Android IPC机制—跨进程的观察者模式

    在AIDL文件中并不是所有的数据类型都可以使用,AIDL支持的数据类型如下: 基本数据类型(int.long.char.boolean.double等) String和CharSequence Lis ...

  10. ValueError: attempted relative import beyond top-level package

    python 项目 在pycharm中, 在某个文件夹下: 右键--> mark directory as --> source root 如何在python脚本或者shell中 用代码实 ...