侦探推理

题目描述

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

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

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

题目类型:

模拟题,暴力

思路:

用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更新为他的名字

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

#include<cstdio>
#include<map>
#include<iostream>
#include<string>
using namespace std;
int n,m,p;
/*用suspect[i,j]记录i对j是不是凶手的判断:
suspect[i,j]=1时,i认为j是凶手;
suspect[i,j]=-1时,i认为j不是凶手;*/
int s[][];
int l[];
int d[][];
int day[][];
int gu[];
map<string,int>t;//用来记名字用
map<int,string>h;
string u,v[],g[],q[],bb;
int main()
{
cin>>m>>n>>p;
for(int i=;i<=m;i++)
{
cin>>u;
t[u]=i;
h[i]=u;
}
for(int i=;i<=p;i++)
{
//cout<<"i "<<i<<endl;
int y,ll=;
u=""; //一个个单词读进来,遇到.?!表示语句结束
while(u[ll-]!='.'&&u[ll-]!='?'&&u[ll-]!='!')
{
cin>>bb;
//cout<<"bb "<<bb<<endl;
if(ll>) u+=' ';
u+=bb;
ll=u.length(); //ll表示整一句的字母数
}
//cout<<"u "<<u<<endl;
//cout<<"ll "<<ll<<endl;
//把证词人名整理好放进v数组里
for(int j=;j<ll&&u[j]!=':';j++)
{
v[i]+=u[j];
y=j;
}
int jj=t[v[i]];//这句话是编号为jj的人说的
int b=-,nn=,uu=;
//b表示第一个单词是人名的话,存放这是第几个人
//y用来标记人名到底几个字符位置
//uu表示输入的句子是不是关于Today is的
//g用于把句子拼接起来
for(int j=y+;j<ll;j++)
{
//如果是关于星期的,就把星期几放到q里
if(!uu) g[i]+=u[j];else q[i]+=u[j];
//查一查此时的g[i]是不是某个人的名字,MIKE is guilty.
//是的话吧第几个人k放到b里,h[k]返回第k个人名字符串
if(!nn&&!uu&&u[j+]==' ')for(int k=;k<=m;k++)if(h[k]==g[i]){b=k;break;}
//第一个单词是人名
if(b!=-&&!nn&&!uu){g[i]=u[j+];j+=;nn=;}
if(g[i]=="Today is ")uu=;
}
//l[jj]表示第jj个人的第几个观点
//s[jj][l[jj]]=3,d[jj][l[jj]++]=b表示第jj个人的第 l[jj]++个观点认为b是凶手
if(g[i]=="I am guilty.")s[jj][l[jj]++]=;
if(g[i]=="I am not guilty.")s[jj][l[jj]++]=;
if(g[i]=="is guilty."){s[jj][l[jj]]=;d[jj][l[jj]++]=b;}
if(g[i]=="is not guilty."){s[jj][l[jj]]=;d[jj][l[jj]++]=b;}
if(g[i]=="Today is ")
{
//s[jj][l[jj]]=5,day[jj][l[jj]++]=1表示第jj个人的第 l[jj]++个观点认为今天是星期一
s[jj][l[jj]]=;
if(q[i]=="Monday.")day[jj][l[jj]++]=;
if(q[i]=="Tuesday.")day[jj][l[jj]++]=;
if(q[i]=="Wednesday.")day[jj][l[jj]++]=;
if(q[i]=="Thursday.")day[jj][l[jj]++]=;
if(q[i]=="Friday.")day[jj][l[jj]++]=;
if(q[i]=="Saturday.")day[jj][l[jj]++]=;
if(q[i]=="Sunday.")day[jj][l[jj]++]=;
}
}
//cout<<"输入完毕"<<endl;
//最后遍历每个人假设他是凶手
for(int i=;i<=m;i++)
{
//遍历今天星期几
for(int j=;j<=;j++)
{
//针对每一个的证词判断他说真话还是假话
//fa统计说谎话的人
//abc统计不真不假的人
int fa=,T,F,abc=;
for(int k=;k<=m;k++)
{
T=F=;
//l[k]表示第k个人说的证词条数(信息数)
for(int kk=;kk<l[k];kk++)
{
//关于凶手
if(s[k][kk]==)if(i==k)T=;else F=;
if(s[k][kk]==)if(i!=k)T=;else F=;
if(s[k][kk]==)if(i==d[k][kk])T=;else F=;
if(s[k][kk]==)if(i!=d[k][kk])T=;else F=;
//关于星期
if(s[k][kk]==)if(j==day[k][kk])T=;else F=;
}
if(T&&F)break;
if(F) fa++;
if(!T&&!F)abc++;
}
if(T&&F)continue;
//如果说谎话的人正好n个或<=n个 ,
//且说谎话的人和不真不假的人比n个多
//gu[i]=1表示第i个人是凶手成立
if(fa==n||fa<=n&&fa+abc>=n)gu[i]=;
}
}
//ans统计有多少人可能是凶手
int ans=;
for(int i=;i<=m;i++)if(gu[i])ans++;
if(!ans)printf("Impossible");
else if(ans>)printf("Cannot Determine");
else for(int i=;i<=m;i++)if(gu[i]){cout<<h[i];break;}
return ;
}

---------------------
作者: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. KMP算法详细分解

    1. 引言 给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题. Knuth-Morris-Pratt 算法(简称 KMP)是解决这一问题的 ...

  2. 【oracle入门】SQL的命令动词

      SQL的功能 命令动词 数据定义 CREATE,DROP,ALTER 数据操纵 SELECT,INSERT,UPDATE,DELETE 数据控制 CRANT,REVOKE

  3. Vue.js devtool插件安装后无法使用的解决办法【最简单有效的解决方法】

    在开发vue相关的项目时,使用vue devtools工具是一件极其有趣的事,你所有的操作都马上给你实时反馈. 然而有时候安装好的工具,在chrome中不显示. 在网上找过多次,一直没有找到有效解决方 ...

  4. JSP中重定向页面没有全屏显示的问题解决

    <script type="text/javascript"> window.onload=function(){ if(window.parent != window ...

  5. Windows服务器修改网站上传文件的大小限制

    ASP程序 方法一: 修改该网站的的最大上传文件的大小限制 在Windows server上会出现上传大小受限制的问题,这是由于windows server的IIS管理器做了限制所致,IIS默认设置是 ...

  6. linux压缩、解压缩和归档工具

    linux基础之压缩.解压缩和归档工具 1.压缩工具 基本介绍 为了减少文件的原来的文件大小而过多的浪费磁盘的存储空间,我们使用压缩后多文件进行存储 压缩工具的介绍 compress:把文件压缩成以. ...

  7. 1945 : 卡贩子Carol

    题目描述 来自F星球的Carol是一个不折不扣的“正版游戏受害者”,在黑色星期五的疯狂购买后,钱包渐空的Carol突然发现TA所使用的游戏交易平台上有个值得留意的地方————集换式卡牌. 集换式卡牌是 ...

  8. angular6 导出json数据到excal表

    1 首先使用npm下载插件依赖的安装包   npm install file-saver --save   npm install xlsx --save   2 引入项目中的ts文件中   impo ...

  9. hdu 1698 (延迟标记+区间修改+区间求和)

    In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. T ...

  10. 【解决】nginx 下$_SERVER['PATH_INFO'] 无法获取到内容

    Apache是模块加载文件的,默认支持$_SERVER['PATH_INFO'] : 而对于Nginx下, 是不支持PATH INFO的, 也就是它不会默认设置PATH_INFO. 而因为Nginx默 ...