UVA 592 - Island of Logic

来源:互联网 发布:借尸还魂事件 知乎 编辑:程序博客网 时间:2024/05/17 06:22

时间限制: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 -2using 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