时间限制:3.000秒
这种题,说难吧不难,但是就是不好做,因为太麻烦,比较练代码能力。
大意是一座岛上有三个种族,神族(divine)永远讲实话,魔鬼(evil)永远在撒谎,而人类(human)比较特殊,白天(day)讲实话晚上(night)撒谎。
输入是多组的,每组都是一些人的陈述,开头会先指出是谁说的,然后跟一个冒号":",然后是他(她,它)说的句子,这些句子都符合如下的格式中的一种:
I am [not] ( divine | human | evil | lying ).
X is [not] ( divine | human | evil | lying ).
It is ( day | night ).
方括号[]里的内容是可能出现也可能不出现的,当然,意思也不相同。而括号()里的内容则是一定有且只有一个词会在一条陈述中出现。讲话的人和第二句中被描述的X以字母代替,可以为ABCDE中的任意一个。
对于每组数据,要求你根据这些陈述判断说话的人和被描述的人的身份,给出能够确定的信息来,也就是说,可能给了5个人的身份你只能推出3个来,那么就把能确定身份的这3个人的信息输出出来。如果给出的描述自相矛盾无解,输出“ This is impossible.”,如果给出的描述得不出任何确定的信息,输出“ No facts are deducible.”,如果有人的身份是可以确定的,则按照如下格式表述这个人的身份:
X is ( divine | human | evil ).
如果白天还是晚上是确定的,也要输出,格式为:
It is ( day | night ).
具体可以参见样例。
解法比较简单,就是枚举所有可能的情况,挨个带进去检查就是了。但是实现起来就略麻烦了……纯练代码能力了吧。
废话少说,上代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define yes 1
#define no 0
#define divine 0
#define human 1
#define evil 2
#define free 0
#define day 3
#define night 4
#define lying 5
#define time -2
using namespace std;
struct information { // 定义每句话的结构体
int speaker, target, real, description; // 每句话的内容设定为讲话者、这句话形同的对象、be动词、描述
};
int Letter2Num(char match[], char l) {
int i;
for(i = 0; match[i] != '0' && match[i] != l && i != 5; ++i);
return i;
}
int GetNum(char match[], string &in) {
cin >> in;
if(in[0] >= 'A' && in[0] <= 'E') {
int i = Letter2Num(match, in[0]);
match[i] = in[0];
return i;
} else if(in == "I") return -1;
else return time;
}
int GetDescription(string &in) {
if(in == "divine.") return divine;
else if(in == "human.") return human;
else if(in == "evil.") return evil;
else if(in == "day.") return day;
else if(in == "night.") return night;
else return lying;
}
void GetStatusAndDescription(information &info, char match[], string &in) {
cin >> in;
cin >> in;
if(in == "not") {
info.real = no;
cin >> in;
info.description = GetDescription(in);
} else {
info.real = yes;
info.description = GetDescription(in);
}
}
void GetInfo(information &info, char match[]) {
string in;
info.speaker = GetNum(match, in);
info.target = GetNum(match, in);
if(info.target == -1) info.target = info.speaker;
GetStatusAndDescription(info, match, in);
}
void PutInfo(char match[], const information &info) {
cout << match[info.speaker] << ": ";
if(info.speaker == info.target) cout << "I am ";
else if(info.target == time) cout << "It is ";
else cout << match[info.target] << " is ";
if(info.real == no) cout << "not ";
switch(info.description) {
case divine:
cout << "divine.";
break;
case human:
cout << "human.";
break;
case evil:
cout << "evil.";
break;
case day:
cout << "day.";
break;
case night:
cout << "night.";
break;
case lying:
cout << "lying";
break;
}
}
string Identity(int ID) {
switch(ID) {
case divine:
return "divine";
case human:
return "human";
case evil:
return "evil";
}
}
bool LastPossibility(int *s, int *e) {
while(s != e) if(*(s++) != 2) return false;
return true;
}
bool NextPossibility(int *s, int *e) {
if(LastPossibility(s, e)) return false;
for(int t = 1; s != e; ++s) {
int temp = ((*s) + t) / 3;
*s = ((*s) + t) % 3;
t = temp;
}
return true;
}
int CalNum(char match[]) {
int i;
for(i = 5; i != 0 && match[i] == '0'; i--);
return i + 1;
}
bool CheckInfo(const information &info, int p[], int m, int t) {
bool ok;
if(info.target == time) {
if(info.description == t) ok = true;
else ok = false;
} else {
if(info.description == lying) {
switch(p[info.target]) {
case divine:
ok = false;
break;
case human:
if(t == day) ok = false;
else ok = true;
break;
case evil:
ok = true;
break;
}
} else {
if(p[info.target] == info.description) ok = true;
else ok = false;
}
}
if(!info.real) ok = !ok;
switch(p[info.speaker]) {
case divine:
break;
case human:
if(t == day);
else ok = !ok;
break;
case evil:
ok = !ok;
break;
}
return ok;
}
bool HaveHuman(int *s, int *e) {
while(s != e) if(*(s++) == human) return true;
return false;
}
void CopyAns(int ans[], int p[], int vis[], int *m, int *dayornight, int resofdayortime, bool *first) {
if(*first) {
for(int i = 0; i != *m; ++i) ans[i] = p[i];
for(int i = 0; i != *m; ++i) vis[i] = 1;
*dayornight = resofdayortime;
*first = false;
} else {
for(int i = 0; i != *m; ++i) if(vis[i] && p[i] != ans[i]) vis[i] = 0;
switch(*dayornight) {
case day:
if(resofdayortime != day) *dayornight = day + night;
break;
case night:
if(resofdayortime != night) *dayornight = day + night;
break;
}
}
}
bool CheckPossibilities(information info[], int *n, int p[], int ans[], int *m, int vis[], int *dayornight, bool *first) {
bool checkday = true, checknight = true;
for(int i = 0; i != *n; ++i) {
if(checkday) checkday = CheckInfo(info[i], p, *m, day);
if(checknight) checknight = CheckInfo(info[i], p, *m, night);
if(!(checkday || checknight)) return false;
}
if(checkday && checknight) CopyAns(ans, p, vis, m, dayornight, day + night, first);
else if(checkday) CopyAns(ans, p, vis, m, dayornight, day, first);
else if(checknight) CopyAns(ans, p, vis, m, dayornight, night, first);
return true;
}
struct Out {
char match;
int ans, vis;
bool operator < (const Out& o) const {
return match < o.match;
}
};
int main() {
int n, t = 0;
char match[10];
while(cin >> n && n) {
cout << "Conversation #" << ++t << endl;
memset(match, '0', sizeof(match));
information info[n];
for(int i = 0; i != n; ++i) GetInfo(info[i], match);
int m = CalNum(match);
int p[m], ans[m], vis[m], dayornight = free;
memset(vis, 0, sizeof(vis));
memset(p, 0, sizeof(p));
bool first = true;
bool haveans = false;
do {
if(CheckPossibilities(info, &n, p, ans, &m, vis, &dayornight, &first)) {
haveans = true;
}
} while(NextPossibility(p, p + m));
if(!haveans) cout << "This is impossible." << endl;
else {
Out o[m];
for(int i = 0; i != m; ++i) o[i].match = match[i], o[i].ans = ans[i], o[i].vis = vis[i];
sort(o, o + m);
bool outans = false;
for(int i = 0; i != m; ++i) if(o[i].vis) {
outans = true;
cout << o[i].match << " is " << Identity(o[i].ans) << "." << endl;
}
switch(dayornight) {
case day:
outans = true;
cout << "It is day." << endl;
break;
case night:
outans = true;
cout << "It is night." << endl;
break;
}
if(!outans) cout << "No facts are deducible." << endl;
}
cout << endl;
}
}