稍稍情况有点麻烦。。。主要是代码写得挫了
给出n句话
让你判断 有什么信息是确定的 ,例如【每个人的身份是否确定】、【当前时间是否确定】
身份有三种,神、人、恶魔,神只说真话,恶魔只说假话,人在白天说真话,在晚上说假话
n句话 里 有肯定句和否定句
可以把每句话 记录到一个结构体
{
每句话记录说话者
1、是否只叙述时间 如【It is ( day | night ). 】
2、是否lying句式, 如【I am [not] lying】,记下肯定还是否定
3、身份句式【X is [not] 身份】 记下 被叙述者,以及身份,以及肯定还是否定
}
因为人数最多只有5种类型,时间只有2种,我们直接枚举所有的身份情况+时间情况,也就是【 3^5 * 2 】
每一种枚举下
我们先 判断本句话是否为真,
再判断说话者 是谁 即可
特判一下impossible的情况 【i am lying】
最后如果方案唯一,则 输出答案
如果合法方案有多种,我们看 在多种方案中,是否有 身份一直不变的人, 是否 时间一直不变,如果有,则它们是确定的。
如果没,输出 【No facts are deducible.】
以下数据是从网上找到的
----------------------------------------------------
6
A: B is human.
A: B is evil.
B: A is human.
C: A is not lying.
B: C is not human.
D: E is not lying.
4
A: I am human.
A: It is night.
B: I am human.
B: It is day.
3
A: I am human.
B: I am human.
A: B is lying.
3
A: I am divine.
B: A is not lying.
A: B is lying.
3
A: I am divine.
B: A is lying.
A: B is lying.
5
A: B is human.
A: B is evil.
B: A is evil.
C: A is not lying.
B: It is day.
5
C: A is not lying.
A: B is human.
A: B is evil.
B: A is evil.
B: It is day.
1
A: A is not lying.
1
A: A is lying.
2
E: E is evil.
E: E is divine.
7
A: It is night.
B: It is day.
C: I am human.
E: C is human.
C: E is divine.
A: B is lying.
B: C is evil.
0
*********************************************************************************
Conversation #1
A is human.
B is divine.
C is evil.
It is night.
Conversation #2
A is evil.
B is human.
It is day.
Conversation #3
It is day.
Conversation #4
This is impossible.
Conversation #5
No facts are deducible.
Conversation #6
A is evil.
B is divine.
C is evil.
It is day.
Conversation #7
A is evil.
B is divine.
C is evil.
It is day.
Conversation #8
No facts are deducible.
Conversation #9
This is impossible.
Conversation #10
E is human.
It is night.
Conversation #11
A is evil.
C is evil.
E is evil.
It is day.
********************************************************************************
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
struct node
{
char spker;
char who;
int is_not;
string what;
int d_or_n;
};
node tm[55];
string ss;
vector<int> sb[55];
set<char> ::iterator it;
int main()
{
int n,i;
int cnt=1;
set<char> sb;
while(scanf("%d",&n)!=EOF&&n)
{
sb.clear();
getchar();
for (i=1;i<=n;i++)
{
getline(cin,ss);
string sub=ss.substr(3,ss.length()-3); //截取除去主语后的一句话
tm[i].d_or_n=-1; // 为-1表示本句话与时间无关
if (sub=="It is day.")
{
tm[i].spker=ss[0]; //记下说话人
tm[i].d_or_n=1;continue; //记下是白天还是黑夜
}
if (sub=="It is night.")
{
tm[i].spker=ss[0];
tm[i].d_or_n=0;continue;
}
if (ss[3]=='I') //‘I’就是说话人自己
ss[3]=ss[0];
tm[i].spker=ss[0];
tm[i].who=ss[3];
sb.insert(tm[i].spker); //计算种类
sb.insert(tm[i].who);
if (ss.find("not")!=string::npos) //如果找不到not,则为肯定句,找到则表示为否定句
tm[i].is_not=0;
else
tm[i].is_not=1;
if (ss.find("divine")!=string::npos) //被认为是什么
tm[i].what="divine";
else if (ss.find("human")!=string::npos)
tm[i].what="human";
else if (ss.find("evil")!=string::npos)
tm[i].what="evil";
else if (ss.find("lying")!=string::npos)
tm[i].what="lying";
}
printf("Conversation #%d\n",cnt++);
string what[6]; //what[i]存第i个人 当前的身份
int k;
int flag=0; // impossible的情况(当且仅当说I am lying.才是此情况)
int kind=sb.size(); //出现的种类数(最后要输出的种类数)
int possible_way=0; //合法的身份方案, 如果仅有一种,则输出,否则表示都多种情况
int all=(int)pow(3.0,5); //枚举范围0-all
string ans[6]; //用来保存 找到合法的身份方案后 的那5个身份
int has_change[6]; //用来记录 找到的多个合法方案中 某人的身份是否一样 (如果一样,表示某个人的身份在什么时候都是确定的,反之则否)
memset(has_change,0,sizeof(has_change));
int ans_d_n=-1; //用来保存 找到合法的身份方案后 的时间,如果一直不变,表示这个时间也是固定的,同has_change数组的理
int has_changed_d_n=0; //记录 合法方案的时间是否改变,理由同上
int line=1; //标志 当前方案是否第一次出现,
int day_night; //时间变量,1为白天,0为黑夜
int twice=0; //枚举 每种方案 在白天 和 黑夜下的情况
for (k=0;k<all;k++)
{
if (twice==1)//第二次 把时间看作黑夜,并且k--回到上个方案
{
twice++;
k--;
day_night=0;
continue;
}
if (twice==0)//第一次 把时间看作白天
{
twice++;
day_night=1;
}
if (twice==2) //复位
twice=0;
int tmp=k;
for (i=1;i<=5;i++) //枚举身份
{
if (tmp%3==0)
what[i]="divine";
else
if (tmp%3==1) what[i]="human";
else
what[i]="evil";
tmp=tmp/3;
}
int find_ans=1; //是否找到一个合法方案
for (i=1;i<=n;i++)
{
if (tm[i].d_or_n!=-1) //如果第i句话与时间相关
{
if (day_night==tm[i].d_or_n) //如果第i句话时间与当前方案时间相同,即本句话为真
{
if (what[tm[i].spker-'A'+1]=="divine") //神族说真话,没问题
continue;
if (what[tm[i].spker-'A'+1]=="evil") //恶魔说真话,本方案不合法,结束
{find_ans=0;break;}
if (what[tm[i].spker-'A'+1]=="human") //人
{
if (day_night==1) continue; //白天说真话,ok
else {find_ans=0;break;} //晚上说真话,本方案不合法,结束
}
}
else //如果第i句话时间与当前方案时间相同,即本句话为假 ,下面的具体就不分析了
{
if (what[tm[i].spker-'A'+1]=="divine")
{find_ans=0;break;}
if (what[tm[i].spker-'A'+1]=="evil")
continue;
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) {find_ans=0;break;}
else continue;
}
}
}
//下面的都是本句话与时间 无关的情况
if (tm[i].what=="lying") //谁谁谁 lying 的情况
{
if (tm[i].is_not==1) //如果说 某人【在】说谎
{
if (tm[i].spker==tm[i].who) //如果自己说自己说谎, 这是唯一的 不可能的方案,flag标记,结束所有方案,输出答案
{flag=1; find_ans=1;break;}
int isreal; //其余情况要先判断 这句话是否为真 (先不考虑说话人,只考虑说的话)
if (what[tm[i].who-'A'+1]=="divine") //神不可能撒谎,本句话为假
isreal=0;
if (what[tm[i].who-'A'+1]=="human") //人类撒谎根据时间
{
if (day_night==1) isreal=0;
else isreal=1;
}
if (what[tm[i].who-'A'+1]=="evil") //恶魔撒谎
isreal=1;
if (isreal) //如果 shuo 的是真话
{
if (what[tm[i].spker-'A'+1]=="divine") //神说真话,合法
continue;
if (what[tm[i].spker-'A'+1]=="human") //人是否合法得看时间
{
if (day_night==0)
{ find_ans=0;break; }
}
if (what[tm[i].spker-'A'+1]=="evil") //恶魔不说真话
{ find_ans=0;break; }
}
else //说的是假话
{
if (what[tm[i].spker-'A'+1]=="divine")
{find_ans=0;break;} //矛盾
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) {find_ans=0;break;} //本应该说真话却说假话
else if (day_night==0) continue; //晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
continue;
}
}
else // //如果说 某人【不在】说谎
{
int isreal; //依旧先判断 话的真假
if (what[tm[i].who-'A'+1]=="divine")
isreal=1;
if (what[tm[i].who-'A'+1]=="human")
{
if (day_night==1) isreal=1;
else isreal=0;
}
if (what[tm[i].who-'A'+1]=="evil")
isreal=0;
if (isreal) //如果 shuo 的是真话
{
if (what[tm[i].spker-'A'+1]=="divine")
continue;
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==0)
{ find_ans=0;break; }
}
if (what[tm[i].spker-'A'+1]=="evil")
{ find_ans=0;break; }
}
else //如果说的是假话
{
if (what[tm[i].spker-'A'+1]=="divine")
{find_ans=0;break;} //矛盾
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) {find_ans=0;break;} //本应该说真话却说假话
else if (day_night==0) continue; //晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
continue;
}
}
}
else //下面的情况 就是 xxx是什么身份 这种句式
{
if (tm[i].is_not==1) //如果是肯定句
{
if (tm[i].what==what[tm[i].who-'A'+1])//与被描述者身份一致,本句为真话
{
if (what[tm[i].spker-'A'+1]=="divine")
continue;
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) continue; //本应该说真话却说假话
else if (day_night==0) {find_ans=0;break;} //晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
{find_ans=0;break;}
}
else //与被描述者身份不一致,本句为假话
{
if (what[tm[i].spker-'A'+1]=="divine")
{find_ans=0;break;} //矛盾
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) {find_ans=0;break;} //本应该说真话却说假话
else if (day_night==0) continue; //晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
continue;
}
}
else //如果整句话是否定句
{
if (tm[i].what==what[tm[i].who-'A'+1]) //与被描述者身份一致,本句为假话
{
if (what[tm[i].spker-'A'+1]=="divine")
{find_ans=0;break;} //矛盾
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) {find_ans=0;break;} //本应该说真话却说假话
else if (day_night==0) continue; //晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
continue;
}
else //与被描述者身份不一致,本句为真话
{
if (what[tm[i].spker-'A'+1]=="divine")
continue;
if (what[tm[i].spker-'A'+1]=="human")
{
if (day_night==1) continue; //本应该说真话却说假话
else if (day_night==0) {find_ans=0;break;}//晚上说假话
}
if (what[tm[i].spker-'A'+1]=="evil")
{find_ans=0;break;}
}
}
}
}
if (flag) //impossible的情况
break;
if (find_ans) //找到一种合法方案
{
int h;
for (h=1;h<=5;h++) //储存答案
{
if (line) //如果是第一次找到合法方案,直接存下来,并在后面去掉首次标记
{
ans[h]=what[h];continue;
}
if (ans[h]!=what[h]) //非第一次找到答案,先比较当前答案与以前的是否一致
{
ans[h]=what[h]; //更新答案并且
has_change[h]=1; //如果不一致,标志这个人的身份是不确定的
}
}
if (ans_d_n!=day_night&&!line) //更新时间,并看是否一直不变
has_changed_d_n=1;
ans_d_n=day_night; //储存时间
possible_way++; //方案数++
line=0;
}
}
if (possible_way==0||flag) //无合法方案,或者遇到flag情况
printf("This is impossible.\n");
else
if (possible_way>1) //方案有很多
{
int has=0; //记录是否有输出过答案
it=sb.begin(); //遍历出现过的人
for (int h=1;h<=kind;h++,it++)
{
int p= (*it)-'A'+1; //出现过的人的编号
if (has_change[p]==0) //如果在多个方案中 身份都一样,则标明身份确定,输出,并更新标记
{
printf("%c is %s.\n",p-1+'A',ans[p].c_str());
has=1; //表示输出过答案
}
}
if (has_changed_d_n==0) //如果时间在多个方案中不曾改变
if (ans_d_n!=-1)
printf("It is %s.\n",(ans_d_n==1)?"day":"night"),has=1; //输出答案并更新标记
if (!has) //如果 人的身份或时间都不是确定的,输出 无法确定事实
printf("No facts are deducible.\n");
}
else //如果方案只有一种。。。。必然就是合法的唯一的方案
{
it=sb.begin();
for (i=1;i<=kind;i++,it++)
{
int p= (*it)-'A'+1;
printf("%c is %s.\n",p-1+'A',ans[p].c_str());
}
if (ans_d_n!=-1)
printf("It is %s.\n",(ans_d_n==1)?"day":"night");
}
printf("\n");
}
return 0;
}