题二 侦探推理
【问题描述】
明明同学最近迷上了侦探漫画《柯南》并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏。游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明明的任务就是找出这个罪犯。接着,明明逐个询问每一个同学,被询问者可能会说:
证词中出现的其他话,都不列入逻辑推理的内容。
明明所知道的是,他的同学中有N个人始终说假话,其余的人始终说真。
现在,明明需要你帮助他从他同学的话中推断出谁是真正的凶手,请记住,凶手只有一个!
【输入格式】
输入由若干行组成,第一行有二个整数,M(1≤M≤20)、N(1≤N≤M)和P(1≤P≤100);
M是参加游戏的明明的同学数,N是其中始终说谎的人数,P是证言的总数。接下来M行,
每行是明明的一个同学的名字(英文字母组成,没有主格,全部大写)。
往后有P行,每行开始是某个同学的名宇,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式。证词每行不会超过250个字符。
输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。
【输出格式】
如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是
罪犯,则输出 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
【思路】
字符串处理+枚举判断。
首先根据输入处理字符串,剔除不符合要求的证言并分清正确证言的主系表以便判断。
其次分别枚举罪犯、日期,这样就能够判断每句话的真实性,也就可以计算出说真话的人数a与说谎话的人数b,只要满足a<=N
&& b<=M-N(因为可能有人不说话)则说明枚举可行。
需要注意的是可能会有多个日期对于同一个罪犯都是可行的,这时候看作一种情况,不输出Cannot Determine,而当有多个罪犯同时满足情况的时候需要输出Cannot Determine,没有罪犯满足则输出Impossible。
详见代码。
【代码】
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<vector> 6 #include<map> 7 using namespace std; 8 9 const int maxn = 100+10; 10 const string days[]={"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}; 11 12 struct Node{ 13 string person,zhu,xi,fou,biao; 14 }; 15 vector<Node> nodes; 16 17 string names[maxn],Sent[maxn]; 18 map<string,int> vis1,vis2,ID; 19 int n,m,p,P,D; 20 string S[maxn]; 21 int liers,unliers; 22 int f_day; 23 24 void make_nodes() { 25 for(int i=0;i<p;i++) { 26 string s=S[i]; 27 string person="",zhu="",xi="",fou="",biao=""; 28 int j=0; 29 while(s[j] != ‘:‘ && s[j]) { 30 person+=s[j]; j++; 31 } 32 j+=2; 33 while(s[j]!=‘ ‘ && s[j]) { 34 zhu+=s[j]; j++; 35 } 36 if(!ID.count(zhu)) { continue; } //else 37 j++; 38 while(s[j]!=‘ ‘ && s[j]) { 39 xi+=s[j]; j++; 40 } 41 if(xi!="am" && xi!="is") { continue; } //else 42 j++; 43 while(s[j]!=‘ ‘&& s[j]!=‘.‘ && s[j]) { 44 fou+=s[j]; j++; 45 } 46 if(fou!="not") { biao=fou; fou=""; } 47 else { 48 j++; 49 while(s[j]!=‘.‘ && s[j]) { 50 biao+=s[j]; j++; 51 } 52 } 53 int f=false; 54 for(int i=0;i<7;i++) if(days[i]==biao) {f=true; f_day=1; break;} 55 if(biao=="guilty") f=true; 56 if(!f) continue; //else 57 58 if(j<s.size()-1 || s[j]!=‘.‘ ||(zhu==""||xi==""||biao=="")) {continue; } //其他的话 59 nodes.push_back((Node){person,zhu,xi,fou,biao}); 60 } 61 } 62 63 inline bool vis1_push(string per) { 64 if(!vis1.count(per)) { 65 vis1[per]=1; liers++; 66 } 67 return true; 68 } 69 inline bool vis2_push(string per) { 70 if(!vis2.count(per)) { 71 vis2[per]=1; unliers++; 72 } 73 } 74 bool solve() { 75 liers=unliers=0; 76 vis1.clear(); vis2.clear(); 77 78 int nc=nodes.size(); 79 for(int i=0;i<nc;i++) { 80 string guilty=names[P],day=days[D]; 81 string person=nodes[i].person,zhu=nodes[i].zhu,xi=nodes[i].xi,fou=nodes[i].fou,biao=nodes[i].biao; 82 if(zhu=="Today" && xi=="is") { 83 if(biao!=day){ vis1_push(person);} else { vis2_push(person); } 84 if(vis1.count(person) && vis2.count(person)) return false; 85 } 86 else 87 if(biao=="guilty") { 88 if(zhu=="I" && xi=="am") { 89 if((fou=="not" && guilty==person) || (fou=="" && guilty!=person)) { vis1_push(person); } 90 else { vis2_push(person); } 91 if(vis1.count(person) && vis2.count(person)) return false; 92 } 93 else if(xi=="is") { 94 if((fou=="not" && guilty==zhu) || (fou=="" && guilty!=zhu)) { vis1_push(person); } 95 else{ vis2_push(person); } 96 if(vis1.count(person) && vis2.count(person)) return false; 97 } 98 } 99 } 100 return (liers<=n && unliers<=m-n); 101 } 102 103 int main() { 104 ios::sync_with_stdio(false); 105 106 cin>>m>>n>>p; 107 for(int i=0;i<m;i++) cin>>names[i] , ID[names[i]]=i; 108 ID["Today"]=ID["I"]=1; 109 string ss ; getline(cin,ss); //读空行 110 for(int i=0;i<p;i++) getline(cin,S[i]); 111 112 make_nodes(); //建立nodes 剔除冗杂信息 分清主系表 113 114 int sum=0,ans; 115 for( P=0 ; P<m ; P++) //枚举罪犯 116 { 117 int sum2=0; 118 for( D=0; D<7; D++) //枚举日期 119 { 120 if(solve()) { sum2=1; ans=P;} 121 } 122 sum += sum2; //注意日期可以多种 123 if(sum>=2) { cout<<"Cannot Determine";return 0; } 124 } 125 if(sum==0) cout<<"Impossible"; 126 else cout<<names[ans]; 127 return 0; 128 }