题目描述

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

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

明明所知道的是,他的同学中有 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: 复制

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

一道巨大的模拟题

在此之前 不懂 字符串 string:: substr() , find() .的同学们自行上网学习一下

主要思路都贴在代码上了

#include<bits/stdc++.h>
using namespace std;
string pp[5]={"am guilty","am not guilty","is guilty.","is not guilty."}; // 记录前4种证词的主体部分
string week[8]={" ","is Monday","is Tuesday","is Wednesday","is Thursday","is Friday","is Saturday","is Sunday"};// 记录日期
string name[1000],s[1000];// 名字,证词的发言人
map<string,int>id;// 名字为string 的人 的编号
int n,m,p;
int v[1000];// 记录编号为i的人有没有已经被确定(为罪犯)了
struct node
{int x,week,per[100];// x -->1为确定说谎了// week --> 他认为的日期 ,,若为0则为没有说明//per --> 他认为编号为i的人的情况,,-1(不是罪犯),0(不清楚),1(是罪犯)vector<int>th_1,th_2;//th_1 --> 他认为是罪犯的人的集合//th_2 --> 他认为不是罪犯的人的集合
}a[100];//每个人的情况(根据证词推出)
int work(int day,int g)//正确日期,,g为罪犯
{int x=0,y=0,i,f1,f2,j; /*x --> 确认 说谎的人y --> 不确认有没有说谎f1 --> 1说过真话   0没说过真话f2 --> 1说过谎话   0没说过谎话   */for(i=1;i<=n;i++){f1=0;f2=0;if(a[i].x||(a[i].week&&a[i].week!=day)) f2=1;//天气说错     if(a[i].week==day) f1=1;//天气说对if(a[i].per[g]==-1) f2=1;//说罪犯不是罪犯if(a[i].per[g]==1) f1=1;//说罪犯是罪犯if(i!=g&&a[i].per[i]==1) f2=1;//不是罪犯说自己是罪犯 if(i==g&&a[i].per[i]==1) f1=1;//罪犯说自己是罪犯 if(i!=g&&a[i].per[i]==-1) f1=1;//不是罪犯说自己不是罪犯 for(j=0;j<a[i].th_1.size();j++)//说不是罪犯的人是罪犯 if(a[i].th_1[j]!=g) f2=1;for(j=0;j<a[i].th_2.size();j++)//说不是罪犯的人不是罪犯 if(a[i].th_2[j]!=g) f1=1;if(f1&&f2) return 0; // 有一个人真话假话都说过 --> 该假设不正确 返回 0if(f2) x++; // 始终说谎的人if(!f1&&!f2) y++;// 不确定的人 没说过真话也没说过假话}if(x>m) return 0; // 说谎的人大于规定值  --> 该假设不正确 返回 0if(x+y<m) return 0; // 确定说谎的人+不确定的人==当前说谎话的人的最大值 < m  --> 该假设不正确 返回 0return 1; // 假设成立
}
int main()
{int i,x,j,y;scanf("%d%d%d",&n,&m,&p);//总人数,说谎的人,证词数for(i=1;i<=n;i++){cin>>name[i]; // 名字id[name[i]]=i; // 该名字的编号}for(i=1;i<=p;i++){cin>>s[i];   // 证词前的名字+':'s[i]=s[i].substr(0,s[i].find(':'));// 把s[i]的':'去掉 ,,取':'前的一段x=id[s[i]];//用x记录发言人的编号getchar();getline(cin,s[i]);//输入证词if(s[i][0]=='I'&&s[i][1]==' '&&s[i][2]=='a'&&s[i][3]=='m')// 如果证词属于前2种 应为'I' 开头的  ,,, 但是应该防范一下 有人名字以'I'开头的或者 叫 'I'的人(我一开始没加后面的一坨,然而也过了){if(s[i].find(pp[0])!=-1)// 句子中存在   am guilty   -->  他认为自己是罪犯a[x].per[x]=1; else if(s[i].find(pp[1])!=-1) a[x].per[x]=-1;// 句子中存在   am not guilty   -->  他认为自己不是罪犯continue;}y=s[i].find(pp[2]); if(y!=-1) // 说明 该证词属于第三种 XXX is guilty.  {s[i]=s[i].substr(0,y-1);  // 将 证词 缩短到前面的人名a[x].per[id[s[i]]]=1;   // 记录 编号为x(之前已经记录过的发言人编号)的人 认为 此人 是罪犯a[x].th_1.push_back(id[s[i]]);  // 将s[i]的编号推入到  "是罪犯" 的集合中continue;}y=s[i].find(pp[3]);if(y!=-1) // 说明 该证词属于第四种 XXX is not guilty. {s[i]=s[i].substr(0,y-1); // 将 证词 缩短到前面的人名a[x].per[id[s[i]]]=-1;  // 记录 编号为x的人 认为 此人 不是罪犯a[x].th_2.push_back(id[s[i]]);  // 将s[i]的编号推入到  "不是罪犯" 的集合中continue;}for(j=1;j<=7;j++)  // 枚举日期{y=s[i].find(week[j]); //如果查找到该日期 则属于第5类证词if(y==-1) continue;  if(!a[x].week) a[x].week=j; // 之前没有记录过,就直接记上else if(a[x].week!=j) a[x].x=1; // 之前记录过,并且还与上次说的不同,说明此人说谎了break;}// 其他证词不予考虑}x=0;// 罪犯的人数y=0;// 当前的罪犯memset(v,0,sizeof(v));for(i=1;i<=7;i++)  // 枚举真实日期{for(j=1;j<=n;j++) // 枚举真实罪犯{if(v[j]) continue; // 之前已经确认过为罪犯的人不予考虑if(work(i,j)){++x;  // 罪犯总人数+1v[j]=1; // 确认 j 为罪犯if(x>=2) // 罪犯人数大于1,,输出不止一个人可能是罪犯{printf("Cannot Determine");return 0;}y=j; // 记录当前罪犯}}}if(y==0) printf("Impossible"); // 没有人被记录 --> 没有人是罪犯else cout<<name[y];return 0;
}

洛谷 P1039 侦探推理 题解相关推荐

  1. 洛谷P1039侦探推理题解--zhengjun

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

  2. 洛谷P1039 侦探推理

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

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

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

  4. 洛谷 P1039 侦探推理

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

  5. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  6. 洛谷P2312 解方程题解

    洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...

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

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

  8. 洛谷P1273 有线电视网 题解

    洛谷P1273 有线电视网 题解 题目链接:P1273 有线电视网 题意: 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为 ...

  9. 洛谷P4568 [JLOI2011] 飞行路线 题解

    洛谷P4568 [JLOI2011] 飞行路线 题解 题目链接:P4568 [JLOI2011] 飞行路线 题意: Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公 ...

最新文章

  1. 使用alterMIME实现添加message footer功能
  2. MyGeneration学习笔记(1) : 使用MyGeneration生成存储过程和数据访问层代码
  3. ibm服务器imm管理方式简介
  4. 读书笔记:《一生的计划》
  5. CCNP-17 OSPF试验13(BSCI)
  6. Lintcode: Permutation Index
  7. “升级 iOS 最新系统后,我弃用了 iPhone!”
  8. 简述数学建模的过程_数学建模研究过程指导(精编版) Part IV
  9. GDAL源码剖析(十)之编写自己的扩展格式
  10. python软件下载百度云-python电子书学习资料打包分享百度云资源下载
  11. k_means算法+python实现
  12. SPOJ Play on Words
  13. python语法学习第十天--类与对象
  14. 破解软件下载网站100个
  15. 论文笔记:针对盲化的 RSA算法的水平聚类侧信道攻击
  16. Java基础——java代码规范详细版
  17. Atlassian与DevOps 系列产品选择方案介绍
  18. 英语谚语精选(English Proverb Collection)
  19. java项目——人机猜拳
  20. 全网最全关闭小米手机MIUI系统广告教程

热门文章

  1. GNN-图卷积模型-2016:PATCHY-SAN【图结构序列化:将图结构转换成了序列结构,然后直接利用卷积神经网络在转化成的序列结构上做卷积】
  2. ubuntu合并终端_如何在Ubuntu中安装多个终端以及更改默认终端
  3. Git让你从入门到精通,看这一篇就够了!
  4. 基于单片机的音乐播放器设计
  5. hdu 2121 最小树形图 +虚根
  6. u盘引导不能识别惠普服务器硬盘,如何解决惠普电脑uefi识别不了u盘
  7. mysql一对多查询_MySQL 一对多查询
  8. 原来微信显示“对方正在输入”,还有这样的含义,真的让人很扎心
  9. Debian10自签CA证书
  10. Windows7+CentOS双系统同一硬盘