直接枚举

niteko 2020-07-29 16:25:27 2020-07-29 16:41:58

直接枚举情况,根本不用让你的程序像人一样思考---yyc001 (luogu)

本题解主要参考上述神仙的代码

/*
	一个神奇的数据 
	2 2 4
	HELLO
	GUILTY
	HELLO: What is your name?
	GUILTY: I am GUILTY.
	GUILTY: Are you guilty?
	HELLO: I am not guilty.
	答案是“HELLO”,但如果不对大小写敏感则只有一句有效的证词
	不说话的人可以当作说真/假话的
*/

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

int m, n, p, nx, fake[22], w[233]; //nx记录上一个罪犯(可能没有)的编号, fake[i]记录第i个人有没有说谎(无法判断就是0), w[i]记录第i句话是谁说的 
string said[233], name[22],day[8]={"hhhh","Today is Sunday.","Today is Monday.","Today is Tuesday.","Today is Wednesday.","Today is Thursday.","Today is Friday.","Today is Saturday."};
bool err; 

void add (int who, int cur) //1:真话 -1:假话 0:不知道 
{
	if (fake[who] && fake[who]!=cur) err = 1;
	else fake[who] = cur;
}

int main()
{
	cin>>m>>n>>p;
	for (int i = 1; i <= m; i++) cin>>name[i];
	for (int i = 1; i <= p; i++)
	{
		string nm; cin>>nm;
		nm.erase(nm.end()-1); //去掉: 
		for (int j = 1; j <= m; j++) 
			if (name[j] == nm)
			{
				w[i] = j; //记录第i句话是谁说的 
				break;
			}
		getline(cin,said[i]); //记录话的内容 
		said[i].erase(said[i].begin());	//去掉空格 
		said[i].erase(said[i].end()-1);//就是这儿awa 
		//把换行符去掉, 如果去掉awa, 自己电脑能过, 不去掉评测能过。
		//(这是来自luogu题解的神奇操作, 但是当时作者好像写反了, 现在这个是对的)
	}

	for (int td = 1; td < 8; td++) //枚举星期 
	{
		for (int zf = 1; zf <= m; zf++) //枚举罪犯 
		{
			err = 0;  
			memset(fake,0,sizeof(fake)); //prework 
			for (int i = 1; i <= p; i++)
			{
				int who = w[i]; //判断语句情况, 可以直接得出人是否说谎  
				if (said[i]=="I am guilty.") add(who,who==zf?1:-1); 
				if (said[i]=="I am not guilty.") add(who,who!=zf?1:-1);
				for (int j = 1; j <= 7; j++) if (said[i] == day[j]) add(who,j==td?1:-1);
				for (int j = 1; j <= m; j++)
				{
					if (said[i]==name[j]+" is guilty.") add(who,j==zf?1:-1);
					if (said[i]==name[j]+" is not guilty.") add(who,j!=zf?1:-1);
				}
			}

			int cnt=0, num=0; //cnt记录说谎人数, num记录不确定的人数(可以看作说真/假话) 
			for (int i = 1; i <= m; i++)
			{
				if (fake[i]==-1) cnt++;
				if (!fake[i]) num++;
			}
			if (!err && cnt<=n && cnt+num>=n) //情况成立 && 说谎人数满足题意 
			{
				if (nx && zf!= nx) //之前有过成立的情况 
				{
					printf("Cannot Determine");
					return 0;
				} 
				else nx = zf; //记录成立情况 
			}
		}
	}

	if (!nx) printf("Impossible"); //没找到罪犯 
	else cout<<name[nx];
	return 0;
}

共 1 条回复

xy0313

%%%