Island of Logic uva 暴力枚举

Island of Logic 

The Island of Logic has three kinds of inhabitants: divine beings that always tell the truth, evil beings that always lie, and human beings that are truthful during the day and lie at night. Every inhabitant recognizes the type of every other inhabitant.

A social scientist wants to visit the island. Because he is not able to distinguish the three kinds of beings only from their looks, he asks you to provide a communication analyzer that deduces facts from conversations among inhabitants. The interesting facts are whether it is day or night and what kind of beings the speakers are.

Input 

The input file contains several descriptions of conversations. Each description starts with an integer  n , the number of statements in the conversation. The following  n  lines each contain one statement by an inhabitant. Every statement line begins with the speaker's name, one of the capital letters  A B C D E , followed by a colon ` : '. Next is one of the following kinds of statements:

  • I am [not] ( divine | human | evil | lying ).
  • X is [not] ( divine | human | evil | lying ).
  • It is ( day | night ).

Square brackets [] mean that the word in the brackets may or may not appear, round brackets () mean that exactly one of the alternatives separated by | must appear. X stands for some name from ABCDE. There will be no two consecutive spaces in any statement line, and at most 50 statements in a conversation.

The input is terminated by a test case starting with n = 0.

Output 

For each conversation, first output the number of the conversation in the format shown in the sample output. Then print `` This is impossible. '', if the conversation cannot happen according to the rules or `` No facts are deducible. '', if no facts can be deduced. Otherwise print all the facts that can be deduced. Deduced facts should be printed using the following formats:

  • X is ( divine | human | evil ).
  • It is ( day | night ).

X is to be replaced by a capital letter speaker name. Facts about inhabitants must be given first (in alphabetical order), then it may be stated whether it is day or night.

The output for each conversation must be followed by a single blank line.

Sample Input 

1
A: I am divine.
1
A: I am lying.
1
A: I am evil.
3
A: B is human.
B: A is evil.
A: B is evil.
0

Sample Output 

Conversation #1
No facts are deducible.

Conversation #2
This is impossible.

Conversation #3
A is human.
It is night.

Conversation #4
A is evil.
B is divine.

解决方案:暴力枚举,要注意分析各种情况。枚举方法我是想不出来,参考了别人的方法。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int STATUSNUM=486;///最大的枚举数,3*3*3*3*3*2,A有三种,B有三种,,,最后night和day这两个情况
const int MAXPERNUM=5;///最大的人数
const int DIVINE=0,HUMAN=1,EVIL=2;
const char name[3][10]={"divine","human","evil"};
const char dn[2][10]={"day","night"};
const int NIGHT=1,DAY=0;
bool state[STATUSNUM];
int possible[MAXPERNUM];
char str[60];
int type(int State,int p)
{
    State>>=1;///去掉对白天和黑夜判断的位
    while(p--) State/=3;///从后往前找,找到存放那个人的状态的位置为止
    return State%3;///可返还0,1,2;代表那三种类
}
int lying(int State,int p)///判断是否为谎话
{
    int t=type(State,p);///确定该state下p的种类
    return (t==EVIL||(t==HUMAN&&(State&1)==NIGHT));///只有EVIL,或HUMAN在晚上是说谎的
}
void input()
{
    gets(str);
    int speaker=str[0]-'A';
    if(str[3]=='I'&&str[4]=='t'){///是day还是night
        for(int i=0;i<STATUSNUM;i++)///枚举每个state[i]
        {
            bool flag=((i&1)==NIGHT&&str[9]=='n')||
                       ((i&1)==DAY&&str[9]=='d');///state的情况与语句的相同flag=true;反之flag=false;
            if(lying(i,speaker)==flag) state[i]=false;///若是speaker谎话,但语句对的,则该state[i]要不得;或speaker真话,但语句错误,state[i]也不符合。
        }
        return ;
    }
    int target=(str[5]=='a'?speaker:(str[3]-'A'));///寻得谈论对象
    int neg=(str[8]=='n');///是否有not
    int t;
    switch(str[8+4*neg])///有not,要跳过
    {

        case 'e':t=EVIL;break;
        case 'h':t=HUMAN;break;
        case 'd':t=DIVINE;break;
        case 'l':
            for(int i=0;i<STATUSNUM;i++)
            {
                if(lying(i,speaker)==(neg^lying(i,target))) state[i]=false;
                ///若speaker说谎,但语句为真,或speaker不说谎,语句为假,该state[i]都不符;
                ///(neg^lying(i,target)判断语句真假。
            }

            return ;

    }
    for(int i=0;i<STATUSNUM;i++)
    {
        if((neg^(t==type(i,target)))==lying(i,speaker)) state[i]=false;
        ///若speaker说谎,但语句为真;或speaker不说谎,语句为假,该state[i]都不符;
        ///(neg^type(i,target)判断语句真假,和上面的差不多。
    }
}
void ouput()
{
    int d_n=-1;///白天或黑夜的判断,初始-1;
    memset(possible,-1,sizeof(possible));///初始化possible,possible最终判断每个人的情况
    for(int i=0;i<STATUSNUM;i++){
        if(state[i]){
           if(d_n!=-1&&(i&1)!=d_n) d_n=-2;///多种情况标为-2;
            else if(d_n==-1) d_n=(i&1);
           for(int j=0;j<MAXPERNUM;j++)///五个都判断,conversation中不出现的人不回影响判断
           {
               if(possible[j]!=-1&&type(i,j)!=possible[j]) possible[j]=-2;///多种情况则标记为-2;
               else if(possible[j]==-1) possible[j]=type(i,j);
           }
        }
    }
    bool deducible=false;
    if(d_n==-1) printf("This is impossible.\n");
    else {
        for(int i=0;i<MAXPERNUM;i++)
           {
              if(possible[i]>=0)
            {printf("%c is %s.\n",i+'A',name[possible[i]]);
            deducible=true;}
           }
            if(d_n>=0)
                {printf("It is %s.\n",dn[d_n]);deducible=true;}
        if(!deducible) printf("No facts are deducible.\n");
    }

}
int main()
{
    int n,k=0;;
    while(scanf("%d",&n)&&n)
    {
        getchar();
        memset(state,true,sizeof(state));
        for(int i=0;i<n;i++)
            input();
            printf("Conversation #%d\n",++k);
        ouput();
        printf("\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值