UVa OJ 592

1、这道题真是折腾了我好几天,感觉需要很强的逻辑学功底才能做出来,目前我还写不出来。。。

2、摘抄了一位网友的题解,变量的名字都是很纯正的英文,感觉像是外国人写的,即使这样,也受益良多。

3、define的运用使程序的可读性一下子提高,枚举的时候也相当巧妙,还有亦或的运用,lying函数的运用。。。

4、首先先判断是否“不可能”,“不可能”的条件是“没有一种枚举情况可能”;再判断能否推断出关于居民的结论;再判断能否推断出关于时间的结论;最后如果能推断出至少一点结论,说明“并不是不能确定结论”,否则打印“不能确定任何结论”,注意和“不可能”区分开来,前者是多种情况符合,后者是没有情况符合。

#include<cstdio>
#define DIVINE 0
#define EVIL 1
#define HUMAN 2
#define DAY 0
#define NIGHT 1
#define MAXPERSONS 5
#define STATENUM 486
using namespace std;
int state[STATENUM];
int type(int state,int p){
    state/=2;
    while(p--) state/=3;
    return(state%3);
}
int lying(int state,int p){
    int daynight,t;
    daynight=state%2;
    t=type(state,p);
    return(t==EVIL||(t==HUMAN&&daynight==NIGHT));
}
void init(){
    for(int i=0;i<STATENUM;i++) state[i]=1;
}
void scanline(){
    int i,neg,speaker,target,t,truee;
    char s[50];
    gets(s);
    speaker=s[0]-'A';
    if(s[3]=='I'&&s[4]=='t'){
        for(int i=0;i<STATENUM;i++){
            truee=((i%2==DAY&&s[9]=='d')||(i%2==NIGHT&&s[9]=='n'));
            if(lying(i,speaker)==truee) state[i]=0;
        }
        return;
    }
    if(s[5]=='a') target=speaker;
    else target=s[3]-'A';
    neg=(s[8]=='n');
    switch(s[8+4*neg]){
        case 'd':t=DIVINE;break;
        case 'e':t=EVIL;break;
        case 'h':t=HUMAN;break;
        case 'l':
        for(int i=0;i<STATENUM;i++){
            truee=neg^lying(i,target);
            if(lying(i,speaker)==truee) state[i]=0;
        }
        return;
    }
    for(int i=0;i<STATENUM;i++){
        truee=neg^(type(i,target)==t);
        if(lying(i,speaker)==truee) state[i]=0;
    }
    return;
}
void output(){
    int deduction,i,j,possible[MAXPERSONS],daynight;
    static int caseno=1;
    char names[3][10]={"divine","evil","human"};
    printf("Conversation #%d\n",caseno++);
    for(int i=0;i<MAXPERSONS;i++)
        possible[i]=-1;
    daynight=-1;
    for(int i=0;i<STATENUM;i++)
       if(state[i]){
          if(daynight!=-1&&daynight!=i%2)
              daynight=-2;
          else if(daynight==-1)
              daynight=i%2;
          for(j=0;j<MAXPERSONS;j++){
              if(possible[j]!=-1&&possible[j]!=type(i,j))
                 possible[j]=-2;
              else if(possible[j]==-1)
                 possible[j]=type(i,j);
          }
       }
       if(daynight==-1)
       {
           printf("This is impossible.\n\n");
           return;
       }
       deduction=0;
       for(int i=0;i<MAXPERSONS;i++){
           if(possible[i]>=0){
              printf("%c is %s.\n",i+'A',names[possible[i]]);
              deduction=1;
           }
       }
       if(daynight>=0){
          printf("It is %s.\n",daynight==DAY?"day":"night");
          deduction=1;
       }
       if(!deduction)
          printf("No facts are deducible.\n");
       printf("\n");
}
int main()
{
    int i,n;
    while(scanf("%d\n",&n)==1&&n){
         init();
         for(int i=0;i<n;i++) scanline();
         output();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值