洛谷P1039 侦探推理(模拟)
侦探推理
题目描述
明明同学最近迷上了侦探漫画《柯南》并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏。游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明明的任务就是找出这个罪犯。接着,明明逐个询问每一个同学,被询问者可能会说:
证词中出现的其他话,都不列入逻辑推理的内容。
明明所知道的是,他的同学中有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"。
输入输出样例
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??
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 侦探推理(模拟)的更多相关文章
- 洛谷 P1039侦探推理
/* 枚举罪犯和星期几,那么所有人说的话是真是假一目了然. 首先一个人不能既说真话又说假话. 即: I am guilty. I am not guilty. 因为非真即假,所以直接判断impossi ...
- [NOIP2003] 提高组 洛谷P1039 侦探推理
题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明 ...
- 洛谷 P1039 侦探推理
题目:https://www.luogu.org/problemnew/show/P1039 分析: 这道题是一道有技术含量的模拟,我们主要是不要让计算机向人一样思考,只需要让他穷举变化的星期几和当罪 ...
- 洛谷P1039侦探推理题解
#include<cstdio> #include<cstring> #include<string> #include<iostream> using ...
- Luogu P1039 侦探推理(模拟+枚举)
P1039 侦探推理 题意 题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯 ...
- 【洛谷P1039】侦探推理
侦探推理 题目链接 这是一道恶心至极的模拟题 我们可以枚举罪犯是谁,今天是星期几,从而判断每个人说的话是真是假 若每个人说的话的真假一致,且说谎话的人数<=k且说真话的人数<=m-k,就是 ...
- 洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)
洛谷P1667 数列 题目描述 给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的.现在你有一个操作可以改变数列,选择一个区间[X,Y]满足\(A_X +A_{ ...
- P1039 侦探推理(洛谷)
昨天做了一个非常神奇的题,告诉我们做题之前一定要好好检测评测姬! 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先 ...
- LUOGU P1039 侦探推理 (字符串+模拟)
传送门 解题思路 一道%你神题,\(string\)好强大啊..首先枚举一个周几,再枚举一个罪犯是谁,然后判断的时候就是枚举所有人说的话.定义\(fAKe[i]\)表示第\(i\)个人说的是真话还是假 ...
随机推荐
- 2019-04-23-day038-数据库的语句
昨日回顾 补充的知识点 server端肯定是确定下来的 mysql的客户端 mysql.exe 直接在命令行就可以运行的 (学习阶段用) navicat等可视化的客户端,是第三方开发的客户端 (开发辅 ...
- centos6.5卸载及安装git
一.卸载原有的git 用whereis git命令来检查是否已经安装了git版本的 再使用命令:yum remove git卸载git 二.安装git (一)官网下载:https://mirrors. ...
- pagerank算法在数学模型中的运用(有向无环图中节点排序)
一.模型介绍 pagerank算法主要是根据网页中被链接数用来给网页进行重要性排名. 1.1模型解释 模型核心: a. 如果多个网页指向某个网页A,则网页A的排名较高. b. 如果排名高A的网页指向某 ...
- 【集合】Java集合框架
Java类库中帮助我们在程序设计中实现了传统的数据结构.本文章跳过理论部分,主要介绍如何使用标准库中的集合类. 1 将集合的接口与实现分离 Java集合类库将接口与实现分离.以队列为例: public ...
- 浏览器h5新建文件 保存到本地(相当于浏览器写文件)
function doSave(value, type, name) { var blob; if (typeof window.Blob == "funct ...
- Image Widget 的几种加入形式
image .asset : 加载资源图片,会使打包时包体过大 image.network :网络资源图片,经常换的或者动态的图片 image file : 本地图片,比如相册 重用属性: fit ...
- vue 新建项目
1. 首先安装node.js,安装时一直点Next,知道Finish就可以安装成功 2. 打开控制命令执行程序cmd,输入node -v ,可以查看node的版本信息,即安装成功,我安装的是v8.12 ...
- Spring事务<tx:annotation-driven/>的理解(Controller使用@Transactional)
在使用Spring的时候,配置文件中我们经常看到 annotation-driven 这样的注解,其含义就是支持注解,一般根据前缀 tx.mvc 等也能很直白的理解出来分别的作用. <tx:an ...
- (转)用JS获取地址栏参数的方法(超级简单)
转自http://www.cnblogs.com/fishtreeyu/archive/2011/02/27/1966178.html 用JS获取地址栏参数的方法(超级简单) 方法一:采用正则表达式获 ...
- Python 特殊方法
1 _int_ 定义在类中,创建类的实例的时候回先调用此方法,用于对该类的一些初始化(例如变量初始化) 2 _str_ def _str_(self): return "this is a ...