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

证词中出现的其他话,都不列入逻辑推理的内容。
明明所知道的是,他的同学中有NN个人始终说假话,其余的人始终说真。
现在,明明需要你帮助他从他同学的话中推断出谁是真正的凶手,请记住,凶手只有一个!
输入输出格式
输入格式:
输入由若干行组成,第一行有三个整数,\(M(1\leq M\leq 20),N(1\leq Nleq M)\)和\(P(1\leq P\leq 100)\);\(M\)是参加游戏的明明的同学数,\(N\)是其中始终说谎的人数,\(P\)是证言的总数。
接下来\(M\)行,每行是明明的一个同学的名字(英文字母组成,没有空格,全部大写)。
往后有\(P\)行,每行开始是某个同学的名宇,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式。证词每行不会超过\(250\)个字符。
输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。
输出格式:
如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是罪犯,则输出"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
思路
我没啥题做了,求推荐好题。 --WYL
P1039. --Uranus
其实根本不是好题,这题太屑了。
这道题的毒瘤从输入开始:输入证词是什么鬼啊,还要判断输入是否合法,这个被我大力模拟写过去了:
while(p--)
{
string str;
getline(cin,str);
string now;
int p;
for(p=0;p<str.length();p++)
if(str[p]==':') break;
else now+=str[p];
int id=0;
for(int i=1;i<=m;i++)
if(name[i]==now)//判断当前是谁
{
id=i;
break;
}
p+=2;
now="";
while(isalpha(str[p])) now+=str[p++];//得到一个单词
p++;
if(now=="I")//说的是自己
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="am")
{
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][id]=1;//记录某人认为的犯人的情况
else if(now=="not")
{
p++;
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][id]=2;
}
}
}
else if(now=="Today")//说的是星期
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="is")
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
for(int i=1;i<=7;i++)
if(now==week[i])
{
day[id][i]=true;//记录某人认为今天是星期几
break;
}
}
}
else//说的是别人
{
int to=0;
for(int i=1;i<=m;i++)
if(name[i]==now)
{
to=i;
break;
}
if(to)
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="is")
{
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][to]=1;
else if(now=="not")
{
p++;
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][to]=2;
}
}
}
}
}
接下来大力枚举说谎的人和说真话的人其实也还好写,然后就是判断当前状况是否可行,特别的难写。在这里,我用ans1记录当前是否已经找到了解,用ans2记录当前找到的犯人:
void judge()
{
memset(vis,false,sizeof vis);
int cnt=0,_cnt=0,guilt=0,true_day=0;
for(int i=1;i<=m;i++)//判断犯人
if(lie[i])//这是个说谎的人
for(int j=1;j<=m;j++)//改假话为真话
if(think[i][j]==1) think[i][j]=2;
else if(think[i][j]==2) think[i][j]=1;
for(int i=1;i<=m;i++)//判断星期
{
if(lie[i]) continue;
int hjj=0;
for(int j=1;j<=7;j++)
if(day[i][j])
{
if(hjj) goto NoSolution;
else hjj=j;
}
if(!true_day) true_day=hjj;
else if(hjj&&hjj!=true_day) goto NoSolution;//无解
}
if(true_day)
for(int i=1;i<=m;i++)
if(lie[i]&&day[i][true_day]) goto NoSolution;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(think[j][i])
{
int state=think[j][i];
for(int k=j+1;k<=m;k++) if(think[k][i]&&think[k][i]!=state) goto NoSolution;//无解
if(state==1) guilt=i,cnt++;//记录嫌疑犯
else if(state==2) _cnt++,vis[i]=true;//记录不是嫌疑犯的人
break;
}
if(cnt==1)
{
if(!ans1) ans1=1,ans2=guilt;
else if(ans1==1&&ans2!=guilt)
{
cout<<"Cannot Determine";//有两个人都可能是犯人
exit(0);
}
}
else if(cnt==2)
{
cout<<"Cannot Determine";//有两个人都可能是犯人
exit(0);
}
else if(_cnt==m-1)//这样也可以判断出犯人,因为n-1个人不可能是犯人
{
for(int i=1;i<=m;i++)//找到犯人
if(!vis[i])
{
guilt=i;
break;
}
if(!ans1) ans1=1,ans2=guilt;
else if(ans1==1&&ans2!=guilt)//判断与上面相同
{
cout<<"Cannot Determine";
exit(0);
}
}
NoSolution:
for(int i=1;i<=m;i++)//回退到判断之前
if(lie[i])
for(int j=1;j<=m;j++)
if(think[i][j]==1) think[i][j]=2;
else if(think[i][j]==2) think[i][j]=1;
}
然后 面向数据编程 就能\(AC\)了。
AC代码
#include<bits/stdc++.h>
using namespace std;
int m,n,p,ans1,ans2;
string name[25],week[8]={"","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
int think[25][25];
bool day[25][7],lie[25],vis[25];
void judge()
{
memset(vis,false,sizeof vis);
int cnt=0,_cnt=0,guilt=0,true_day=0;
for(int i=1;i<=m;i++)
if(lie[i])
for(int j=1;j<=m;j++)
if(think[i][j]==1) think[i][j]=2;
else if(think[i][j]==2) think[i][j]=1;
for(int i=1;i<=m;i++)
{
if(lie[i]) continue;
int hjj=0;
for(int j=1;j<=7;j++)
if(day[i][j])
{
if(hjj) goto NoSolution;
else hjj=j;
}
if(!true_day) true_day=hjj;
else if(hjj&&hjj!=true_day) goto NoSolution;
}
if(true_day)
for(int i=1;i<=m;i++)
if(lie[i]&&day[i][true_day]) goto NoSolution;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(think[j][i])
{
int state=think[j][i];
for(int k=j+1;k<=m;k++) if(think[k][i]&&think[k][i]!=state) goto NoSolution;
if(state==1) guilt=i,cnt++;
else if(state==2) _cnt++,vis[i]=true;
break;
}
if(cnt==1)
{
if(!ans1) ans1=1,ans2=guilt;
else if(ans1==1&&ans2!=guilt)
{
cout<<"Cannot Determine";
exit(0);
}
}
else if(cnt==2)
{
cout<<"Cannot Determine";
exit(0);
}
else if(_cnt==m-1)
{
for(int i=1;i<=m;i++)
if(!vis[i])
{
guilt=i;
break;
}
if(!ans1) ans1=1,ans2=guilt;
else if(ans1==1&&ans2!=guilt)
{
cout<<"Cannot Determine";
exit(0);
}
}
NoSolution:
for(int i=1;i<=m;i++)
if(lie[i])
for(int j=1;j<=m;j++)
if(think[i][j]==1) think[i][j]=2;
else if(think[i][j]==2) think[i][j]=1;
}
void dfs(int now,int tot)
{
if(tot==n)
{
judge();
return ;
}
if(now>m||m-now+1+tot<n) return ;
lie[now]=true;
dfs(now+1,tot+1);
lie[now]=false;
dfs(now+1,tot);
}
int main()
{
cin>>m>>n>>p;
for(int i=1;i<=m;i++) cin>>name[i];
getchar();
getchar();
while(p--)
{
string str;
getline(cin,str);
string now;
int p;
for(p=0;p<str.length();p++)
if(str[p]==':') break;
else now+=str[p];
int id=0;
for(int i=1;i<=m;i++)
if(name[i]==now)
{
id=i;
break;
}
p+=2;
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="I")
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="am")
{
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][id]=1;
else if(now=="not")
{
p++;
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][id]=2;
}
}
}
else if(now=="Today")
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="is")
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
for(int i=1;i<=7;i++)
if(now==week[i])
{
day[id][i]=true;
break;
}
}
}
else
{
int to=0;
for(int i=1;i<=m;i++)
if(name[i]==now)
{
to=i;
break;
}
if(to)
{
now="";
while(isalpha(str[p])) now+=str[p++];
p++;
if(now=="is")
{
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][to]=1;
else if(now=="not")
{
p++;
now="";
while(isalpha(str[p])) now+=str[p++];
if(now=="guilty"&&str[p]=='.') think[id][to]=2;
}
}
}
}
}
dfs(1,0);
if(ans1) cout<<name[ans2];
else
{
if(n==m) cout<<"Cannot Determine";
else cout<<"Impossible";
}
return 0;
}
Luogu P1039 侦探推理(模拟+枚举)的更多相关文章
- LUOGU P1039 侦探推理 (字符串+模拟)
传送门 解题思路 一道%你神题,\(string\)好强大啊..首先枚举一个周几,再枚举一个罪犯是谁,然后判断的时候就是枚举所有人说的话.定义\(fAKe[i]\)表示第\(i\)个人说的是真话还是假 ...
- 洛谷P1039 侦探推理(模拟)
侦探推理 题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情 ...
- P1039 侦探推理
题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明 ...
- [NOIP2003] 提高组 洛谷P1039 侦探推理
题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明 ...
- P1039 侦探推理(洛谷)
昨天做了一个非常神奇的题,告诉我们做题之前一定要好好检测评测姬! 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先 ...
- 洛谷 P1039 侦探推理
题目:https://www.luogu.org/problemnew/show/P1039 分析: 这道题是一道有技术含量的模拟,我们主要是不要让计算机向人一样思考,只需要让他穷举变化的星期几和当罪 ...
- 洛谷 P1039侦探推理
/* 枚举罪犯和星期几,那么所有人说的话是真是假一目了然. 首先一个人不能既说真话又说假话. 即: I am guilty. I am not guilty. 因为非真即假,所以直接判断impossi ...
- 洛谷P1039侦探推理题解
#include<cstdio> #include<cstring> #include<string> #include<iostream> using ...
- 【洛谷P1039】侦探推理
侦探推理 题目链接 这是一道恶心至极的模拟题 我们可以枚举罪犯是谁,今天是星期几,从而判断每个人说的话是真是假 若每个人说的话的真假一致,且说谎话的人数<=k且说真话的人数<=m-k,就是 ...
随机推荐
- NX二次开发-NXOpen获取边的端点NXOpen::Edge::GetVertices
NX9+VS2012 #include <NXOpen/Features_BlockFeatureBuilder.hxx> #include <NXOpen/Features_Fea ...
- jsp-application应用
application有两种应用,1是当作map,代码如下 <body> <%! int i=1; %> <% application.setAttribute(&quo ...
- js 事件驱动原理
还记得当初学JAVA-GUI编程时学习过事件监听机制,此时再学习JavaScript中的事件驱动机制,不免简单.当初学习时也是画过原理图,所以从原理图开始吧! js是采用事件驱动(event-driv ...
- DRF的请求响应组件
目录 DRF的请求响应组件 请求模块(request) 概念 request源码简单分析 响应模块(response) 概念 使用方法 response源码简单分析: 解析模块(parse) 概念 使 ...
- 2019-2020 Saint-Petersburg Open High School Programming Contest (SpbKOSHP 19)
2019-2020 Saint-Petersburg Open High School Programming Contest (SpbKOSHP 19) easy: ABFGHI medium-ea ...
- LeetCode 67. Add Binary【个位补0,不必对齐】【easy】
Given two binary strings, return their sum (also a binary string). The input strings are both non-em ...
- Django 分页器模板
返回链接: djang ORM 分页器模板: class Pagination(object): def __init__(self,current_page,all_count,per_page_n ...
- 编译 GNU binutils
重新以 arm 用户登陆,让新设置的环境变量起作用. [arm@localhost arm]#su arm [arm@localhost arm]#cd ${SRC} [arm@localhost t ...
- TwainCapabilities
Twain Capabilities 2013年10月15日 ⁄ 综合 ⁄ 共 6098字 ⁄ 字号 小 中 大 ⁄ 评论关闭 转自:http://blog.163.com/lvan100@yeah/ ...
- 解决VS2012新建MVC4等项目时,收到此模板加载程序集“NuGet.VisualStudio.Interop…”的错误
1.错误如图所示: 2.不管是VS2012,还是2013如果开始没安装Nuget包都或报这个错,因为VS2012就已经全面切换到使用NuGet这个第三方开源工具来管理项目包和引用模块了,使用VS201 ...