[NOIP2003提高组]侦探推理

Posted Mrsrz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2003提高组]侦探推理相关的知识,希望对你有一定的参考价值。

题目:洛谷P1039、Vijos P1106、codevs1089。

题目大意:给你一系列证词,要你求出谁是凶手。具体题目见原题。

解题思路:我们枚举犯人和星期,一个一个进行判断。如果成功则记录答案,如果成功且以前已经记录了答案,则说明有多个凶手,输出“Cannot Determine”,如果最后没有答案,则输出“Impossible”。主要是字符串的处理。其他细节见代码注释。

然而我的初始代码用了getline,在Linux下最后会读入Windows的换行符!!这个问题我找了半天!!后来我把代码稍微改了一下(代码第85~87行的处理),使其兼容Linux和Windows(洛谷和codevs是Linux的,Vijos是Windows的)。

C++ Code:

#include<iostream>
#include<cstring>
#include<string>
#include<map>
#include<cstdlib>
using namespace std;
const string days[]={
	"Today is Monday.",
	"Today is Tuesday.",
	"Today is Wednesday.",
	"Today is Thursday.",
	"Today is Friday.",
	"Today is Saturday.",
	"Today is Sunday."
};
map<string,int>num;//记录编号 
string name[22];//名字 
int n,m,p,cnt,ans,TF[102],T,F;//T表示当前说真话的人数,F表示当前说假话的人数,TF[i]表示i说真话还是假话 
struct word{//id是说这句话的人的编号,st是说的话 
	int id;
	string st;
}f[102];
string s;
bool pdTF(int id,bool b){//判断是否有冲突,返回1表示有冲突 
	if(TF[id]==-1){
		TF[id]=b;
		if(b)++T;else ++F;
	}else{
		if(TF[id]==b)return 0;else return 1;
	}
	if(F>m||T>n-m)return 1;
	return 0;
}
void Judge(int Xs,string day){//测试,若有冲突则直接跳出来 
	memset(TF,-1,sizeof(TF));
	T=F=0;
	for(int i=1;i<=p;++i){
		int pos;
		pos=f[i].st.find("I am guilty.");
		if(~pos){
			if(pdTF(f[i].id,f[i].id==Xs))return;
		}
		pos=f[i].st.find("I am not guilty.");
		if(~pos){
			if(pdTF(f[i].id,f[i].id!=Xs))return;
		}
		pos=f[i].st.find(" is guilty.");
		if(~pos){
			string now=f[i].st;
			now.erase(pos,11);
			int id=num[now];
			if(pdTF(f[i].id,id==Xs))return;
		}
		pos=f[i].st.find(" is not guilty.");
		if(~pos){
			string now=f[i].st;
			now.erase(pos,15);
			int id=num[now];
			if(pdTF(f[i].id,id!=Xs))return;
		}
		pos=f[i].st.find("Today is ");
		if(~pos){
			if(pdTF(f[i].id,f[i].st==day))return;
		}
	}
	/*全部语句检测完毕,没有冲突*/
	if(ans&&ans!=Xs){//已有答案但不是当前凶手,说明有多个凶手 
		cout<<"Cannot Determine"<<endl;
		exit(0);//直接结束程序 
	}
	ans=Xs;
}
int main(){
	cin>>n>>m>>p;
	for(int i=1;i<=n;++i){
		cin>>name[i];
		num[name[i]]=i;
	}
	for(int i=1;i<=p;++i){
		cin>>s;
		s.erase(s.length()-1,1);
		f[i].id=num[s];
		getline(cin,f[i].st);
		f[i].st.erase(0,1);
		char ch=f[i].st[f[i].st.length()-1];
		if(ch==‘\n‘||ch==‘\r‘||ch==‘ ‘)
		f[i].st.erase(f[i].st.length()-1,1);
	}
	ans=0;
	for(int i=1;i<=n;++i)
	for(int j=0;j<7;++j)
	Judge(i,days[j]);
	if(!ans)//没有搜到凶手 
	cout<<"Impossible"<<endl;else
	cout<<name[ans]<<endl;
	return 0;
}

 

以上是关于[NOIP2003提高组]侦探推理的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2003提高组

水王争霸(2003noip提高组)

提高字符串习题

noip2003提高组题解

[NOIP2003] 提高组 洛谷P1040 加分二叉树

P1041 [2003NOIP提高组]传染病控制