| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
暴力枚举+模拟,有点繁琐,内附代码+报告直接暴力,代码写得有点挫。。。
我的报告:http://blog.csdn.net/viphong/article/details/50198029
下面是代码+详细注释
#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;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator