侦探推理

题目描述

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

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

明明所知道的是,他的同学中有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. awk统计文本里某一列重复出现的次数

    比如这样的场景:现在有一个文本,里面是这样的内容: NOTICE: 12-14 15:11:13:  parser. * 6685  url=[http://club.pchome.net/threa ...

  2. centos7.5 时间设置

    # ----- 设置时间同步+时区(上海) ----- rpm -qa ntp || yum -y install ntp systemctl enable ntpd timedatectl set- ...

  3. PCP

    1, What is PCP?Prior Comparable Period2, Why needs PCP?This is to compare the value with history val ...

  4. 2.3 i++/i--与++i/--i的运算

    一.i++/i--: i先参与运算,运算完成后自加/减1: public class Test{ public static void main(String[] args){ // [1] ; i+ ...

  5. 2018.5.3 maven

     1  maven基本概念  1.1maven是什么 1)软件项目管理和理解工具      2)项目对象模型(Project Object Model,POM)      3)项目的构建.报告和文档的 ...

  6. HtmlUnit学习总结

    HtmlUnit学习总结 转载 2016年09月13日 15:58:25 标签: htmlunit / 爬虫 7304 本文摘抄其他博客或者技术论坛,自己搜集整理如下: HtmlUnit学习总结 摘要 ...

  7. asd短片数篇

    黄乙己 黄乙己是站着AK而正常的唯一的人.他身材挺高大:蜡黄脸色,眼角间时常夹着些饼干屑:一副黑色的眼镜.虽然挺正常,可是他有良好的饮食习惯,似乎十多个月都是吃的牛奶泡饭,也没有洗饭盒.他对人说话,总 ...

  8. L1-043 阅览室

    天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者借书时,管理员输入书号并按下S键,程序开始计时:当读者还书时,管理员输入书号并按下E键,程序结束计时.书号为不超过1000的正整数.当管理员将0 ...

  9. 将 windows 目录结构 复制到 linux 上

    思路:生成目录结构文件,复制到linux上,然后建立每个文件即可 借助unix_utils( https://sourceforge.net/projects/unxutils/) 1. window ...

  10. api接口的记录

    http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.billboard.billList&type=1& ...