【洛古 P1039 】[NOIP2003 提高组] 侦探推理

10 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述


解题思路
QAQ
大大大大大大大大暴力

对于证词的内容判断,采用say[i].substr(a,n)截取,表示从a开始截取n个字符。

z f , n z f , d a t zf,nzf,dat zf,nzfdat可以分别储存每个人的证词中的信息,分别为他指明的罪犯是谁,罪犯不是谁,今天的日期。

然后枚举罪犯分别是谁,check每种情况下每个人的证词是否有出入,这里可以用azf[25],adat[10],表示那些人被指认为罪犯,那些人不是罪犯,以及那些日期不是今天。

Tips:

  1. 日期只有一个是真的,不能同时成立
  2. 只有一个人不确定,其他人都不是罪犯,那个人就是罪犯
  3. 考虑完所有情况后,有几个人都可能是罪犯(在某些情况中,他们可以被准确推断为唯一罪犯)属于Cannot Determine
  4. 考虑完所有情况后,都没有一种能准确推断唯一罪犯,即有些情况不矛盾但不唯一确认,就是Cannot Determine

代码

#include<bits/stdc++.h>
using namespace std;


map<string,int>mp,date;
bool flag,flag1;
int m,n,P;
string name[25],p[110],say[110],ps[110],s,ss,ans;
int zf[110],dat[110],nzf[110],v[25];
int azf[25],adat[10],da;
char c;

bool check(){
	bool ok=1;
	da=0;
	memset(azf,0,sizeof(azf));
	memset(adat,0,sizeof(adat));
	for(int i=1;i<=P;i++)
	{
		if(v[mp[ps[i]]]==1)
		{
			if(zf[i]!=0)
			{
				if(azf[zf[i]]==0)
					azf[zf[i]]=2;//1为罪犯,2为非罪犯
				else if(azf[zf[i]]==1)
				{
					ok=0;
					break;
				}
			}
			if(nzf[i]!=0)
			{
				if(azf[nzf[i]]==0)
				{
					azf[nzf[i]]=1;
				}
					
				else if(azf[nzf[i]]==2)
				{
					ok=0;
					break;
				}
			}
			if(dat[i]!=0)
			{
				if(adat[dat[i]]==0)
					adat[dat[i]]=2;
				else if(adat[dat[i]]==1)
				{
					ok=0;
					break;
				}
			}
		}
		else
		{
			if(zf[i]!=0)
			{
				if(azf[zf[i]]==0)
					azf[zf[i]]=1;
				else if(azf[zf[i]]==2)
				{
					ok=0;
					break;
				}
			}
			if(nzf[i]!=0)
			{
				if(azf[nzf[i]]==0)
					azf[nzf[i]]=2;
				else if(azf[nzf[i]]==1)
				{
					ok=0;
					break;
				}
			}
			if(dat[i]!=0)
			{
				if(adat[dat[i]]==2)
				{
					ok=0;
					break;
				}
				if(da==0)	
					adat[dat[i]]=1,da=dat[i];
				else if(da!=dat[i])
				{
					ok=0;
					break;
				}
			}
		}
	}
	if(ok==1)return 1;
	else return 0;
}
void work(int dep,int last)
{
	if(dep>n)
	{
		if(check()==1)
		{
		
			flag1=1;//此情况不矛盾
			string anss;
			int cnt=0,okk=0,t=0;
			for(int i=1;i<=m;i++)
			{
				if(azf[i]==1)
				{
					if(okk)
						return;	
					anss=name[i];
					okk=1;
				}
				if(azf[i]==2)
					cnt++;	
				if(azf[i]!=2)t=i;
			}	
			if(cnt==m-1){
				okk=1;	
				anss=name[t];
			}	
			if(flag)
			{
				if(ans!=anss)//tips3
				{
					printf("Cannot Determine\n");
					flag=-1;
					return;	
				}
			}
			else if(okk){
				flag=1;
				ans=anss;
			}
		}
		return;		
	}
	if(last>m)return;
	if(flag==-1)return;
	if(n-dep+1>m-last+1)
		return;
	for(int i=last;i<=m;i++)
	{
		v[i]=1;
		work(dep+1,i+1);
		if(flag==-1)return;
		v[i]=0;
	}
}

int main(){
	freopen("logic.in","r",stdin);
	freopen("logic.out","w",stdout);
	date["Monday."]=1;date["Tuesday."]=2;date["Wednesday."]=3;date["Thursday."]=4;	date["Friday."]=5;	date["Saturday."]=6;date["Sunday."]=7;
	scanf("%d%d%d",&m,&n,&P);

	for(int i=1;i<=m;i++)
	{
		cin>>name[i];
		mp[name[i]]=i;
	}	

	for(int i=1;i<=P;i++)
	{
		cin>>p[i];
		s=p[i].substr(0,p[i].size()-1);
	
		ps[i]=s;
		getline(cin,say[i]);	
		int len=say[i].size();
		if(say[i]==" I am guilty.")
		{
			zf[i]=mp[s];
			continue;
		}
		if(say[i]==" I am not guilty.")
		{
			nzf[i]=mp[s];
			continue;
		}
		ss=say[i].substr(0,10);
		if(ss==" Today is ")
		{
		//cout<<i<<endl;
			ss=say[i].substr(10,len-3);
			dat[i]=date[ss];
		//	cout<<dat[i]<<endl;
			continue;
		}
		for(int j=0;j<len;j++)
		{
			if(say[i][j]=='i')
			{
				ss=say[i].substr(j);
				if(ss=="is not guilty.")
				{
					ss=say[i].substr(1,j-2);
					nzf[i]=mp[ss];
				}
				if(ss=="is guilty.")
				{
					ss=say[i].substr(1,j-2);
					zf[i]=mp[ss];
				}
			}
		}
	}	

	work(1,1);
	if(flag==1)
		cout<<ans;
	else if(flag1==1)
			printf("Cannot Determine\n");
	else printf("Impossible\n");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值