UVA 592 - Island of Logic

时间限制:3.000秒

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=533&mosmsg=Submission+received+with+ID+14904418


  这种题,说难吧不难,但是就是不好做,因为太麻烦,比较练代码能力。

  大意是一座岛上有三个种族,神族(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;
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值