【洛谷1039】侦探推理(字符串模拟题)

点此看题面

  • (m)个人,其中有一个罪犯。已知(n)个人始终说假话,其余人始终说真话。
  • (p)句证词,分下列五种格式:(不属于任何格式的证词需要忽略)
    • I am guilty.:我是罪犯。
    • I am not guilty.:我不是罪犯。
    • XXX is guilty.:XXX是罪犯。
    • XXX is not guilty.:XXX不是罪犯。
    • Today is XXX.:今天是XXX。其中XXX为Monday~Sunday
  • 需要找出谁是罪犯,或判断无解或有多种可能。
  • (mle20,ple100,|S|le250)

字符串模拟

直接枚举谁是罪犯,今天是星期几,判断始终说假话人数是否小于等于(n),始终说真话人数是否小于等于(m-n)。(之所以这么判是因为可能有只说废话或不说话的人)

判断显然是很简单的,主要涉及一些对字符串的操作。因此这里简单记录一下通过这题学到的几种字符串函数用法:

  • getline(cin,s):读入字符串(s)
  • s.erase(p,l):从(s)(p)个字符开始删去(l)个字符。
  • s.substr(p,l):返回从(s)(p)个字符开始连续(l)个字符构成的子串。

代码:(O(mp))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 20
#define P 100
#define S 250
using namespace std;
const string Day[7]={"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
int m,n,p,u[P+5],f[M+5];string g[M+5],w[P+5],s[P+5];map<string,int> id,dt;
I bool U(CI id,bool v) {return id?(f[id]==(v^1)?0:(f[id]=v,1)):1;}//id说话的真假性为v,判是否矛盾
int main()
{
	RI i;for(i=0;i^7;++i) dt[Day[i]]=i;
	for(scanf("%d%d%d",&m,&n,&p),i=1;i<=m;++i) cin>>g[i],id[g[i]]=i;
	for(i=1;i<=p;++i) cin>>w[i],u[i]=id[w[i].substr(0,w[i].size()-1)],
		getline(cin,s[i]),s[i].erase(0,1),s[i].erase(s[i].size()-1,1);//注意,因为线上评测问题,getline会多读入一个
,需要删去末尾字符
	RI j,k,t0,t1,ans=0;for(i=1;i<=m;++i) for(j=0;j^7&&ans^i;++j)//枚举罪犯是谁,今天是星期几
	{
		for(k=1;k<=m;++k) f[k]=-1;for(k=1;k<=p;++k)//枚举每一句证词
		{
			if(s[k]=="I am guilty."&&!U(u[k],u[k]==i)) goto End;//我是罪犯
			if(s[k]=="I am not guilty."&&!U(u[k],u[k]^i)) goto End;//我不是罪犯
			if(s[k].size()>10&&s[k].substr(s[k].size()-11,11)==//XXX是罪犯
				" is guilty."&&!U(u[k],id[s[k].substr(0,s[k].size()-11)]==i)) goto End;
			if(s[k].size()>14&&s[k].substr(s[k].size()-15,15)==//XXX不是罪犯
				" is not guilty."&&!U(u[k],id[s[k].substr(0,s[k].size()-15)]^i)) goto End;
			if(s[k].size()>10&&s[k].substr(0,9)=="Today is "&&//今天是XXX
				dt.count(s[k].substr(9,s[k].size()-10))&&!U(u[k],dt[s[k].substr(9,s[k].size()-10)]==j)) goto End;
		}
		for(t0=t1=0,k=1;k<=m;++k) !f[k]&&++t0,f[k]==1&&++t1;if(t0>n||t1>m-n) goto End;//如果始终说假话/真话人数不符
		if(ans) return puts("Cannot Determine"),0;ans=i;End:;//判多种可能
	}return ans?(cout<<g[ans]<<endl,0):puts("Impossible"),0;//判无解
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1039.html