Sunday, March 24, 2013

UVa 592 - Island of Logic

Accepted date: 2012-04-01
Ranking (as of 2013-03-24): 138
Language: C++

/*
  UVa 592 - Island of Logic

  To build using Visual Studio 2008:
    cl -EHsc -O2 island_of_logic.cpp
*/

/*
Details for a few cases:

1
A: I am divine.

  day/night A   deducible
  --------------------------------
  d     d(ivine)  o
  d     e(vil)    o
  d     h(uman)   x
  n     d     x
  n     e     o
  n     h     o

  day or night, A = divine or evil or human

1
A: I am lying.

  day/night A   deducible
  --------------------------------
  d     d(ivine)  x
  d     e(vil)    x
  d     h(uman)   x
  n     d     x
  n     e     x
  n     h     x

  impossible

2
D: E is human.
D: E is evil.

  day/night D     E   deducible
  --------------------------------------------
  d     d(ivine)  d     x
  d     d     e(vil)    x
  d     d     h(uman)   x
  d     e     d     o
  d     e     e     x
  d     e     h     x
  d     h     d     x
  d     h     e     x
  d     h     h     x

  n     d(ivine)  d     x
  n     d     e(vil)    x
  n     d     h(uman)   x
  n     e     d     o
  n     e     e     x
  n     e     h     x
  n     h     d     o
  n     h     e     x
  n     h     h     x

  day or night, D = evil or human, E = divine

3
E: I am not human.
D: E is evil.
D: It is day.

  day/night D     E   deducible
  --------------------------------------------
  d     d(ivine)  d     x
  d     d     e(vil)    x
  d     d     h(uman)   x
  d     e     d     x
  d     e     e     x
  d     e     h     x
  d     h     d     x
  d     h     e     x
  d     h     h     x

  n     d(ivine)  d     x
  n     d     e(vil)    x
  n     d     h(uman)   x
  n     e     d     o
  n     e     e     x
  n     e     h     o
  n     h     d     o
  n     h     e     x
  n     h     h     o

  night   D = evil or human, E = divine or human
*/

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cstring>
using namespace std;

const int nr_speakers_max = 'E' - 'A' + 1;
enum {unknown = -1, divine, evil, human};
enum {day, night};
enum {divine_deduced = 1 << divine, evil_deduced = 1 << evil,
  human_deduced = 1 << human};
enum {day_deduced = 1 << day, night_deduced = 1 << night};

bool is_correct_statement(int day_or_night, const vector<int>& speakers,
  const char* p)
{
  int referrer = speakers[*p - 'A'];
  p += 3;
  if (*p == 'I' && *(p + 1) == 't') { // "It is ..."
    p += 6;
    if (!strncmp(p, "day", strlen("day")))
      return day_or_night == day;
    else // "night."
      return day_or_night == night;
  }
  else {
    int referred = (*p == 'I') ? referrer : speakers[*p - 'A'];
    p += 5;
    if (!strncmp(p, "divine", strlen("divine")))
      return referred == divine;
    else if (!strncmp(p, "evil", strlen("evil")))
      return referred == evil;
    else if (!strncmp(p, "human", strlen("human")))
      return referred == human;
    else if (!strncmp(p, "lying", strlen("lying")))
      return referred == evil || referred == human && day_or_night == night;
    else if (!strncmp(p, "not divine.", strlen("not divine")))
      return referred != divine;
    else if (!strncmp(p, "not evil", strlen("not evil")))
      return referred != evil;
    else if (!strncmp(p, "not human", strlen("not human")))
      return referred != human;
    else // "not lying."
      return referred == divine || referred == human && day_or_night == day;
  }
}

bool are_statements_deducible(int day_or_night, const vector<int>& speakers,
  const vector< vector<string> >& statements)
{
  for (int i = 0; i < nr_speakers_max; i++)
    if (speakers[i] != -1) {
      for (size_t j = 0; j < statements[i].size(); j++) {
        if (speakers[i] == divine || speakers[i] == human && day_or_night == day)
        {
          if (!is_correct_statement(day_or_night, speakers,
            statements[i][j].c_str()))
            return false;
        }
        else {
          // speakers[i] == evil || speaker[i] == human && day_or_night == night
          if (is_correct_statement(day_or_night, speakers,
            statements[i][j].c_str()))
            return false;
        }
      }
    }
  return true;
}

void deduce_inhabitants(int day_or_night, int si, vector<int>& speakers,
  const vector< vector<string> >& statements,
  int& deduced_day_or_night, vector<int>& deduced_speakers)
{
  while (si < nr_speakers_max && speakers[si] == -1)
    si++;
  if (si < nr_speakers_max) {
    for (int i = divine; i <= human; i++) {
      speakers[si] = i;
      deduce_inhabitants(day_or_night, si + 1, speakers, statements,
        deduced_day_or_night, deduced_speakers);
    }
  }
  else {
    if (are_statements_deducible(day_or_night, speakers, statements)) {
      // record the deduced facts (day or night, inhabitant types)
      deduced_day_or_night |= 1 << day_or_night;
      for (int i = 0; i < nr_speakers_max; i++)
        if (speakers[i] != -1)
          deduced_speakers[i] |= 1 << speakers[i];
    }
  }
}

int main()
{
  for (int c = 1; ; c++) {
    string line;
    getline(cin, line);
    istringstream iss(line);
    int n;
    iss >> n;
    iss.clear();
    if (!n)
      break;
    vector<int> speakers(nr_speakers_max, -1);
      // speakers[i] is the type of ('A' + i)-th speaker, or -1 if not appeared
    vector<int> deduced_speakers(nr_speakers_max, -1);
      // deduced_speakers[i] is the deduced type(s) of ('A' + i)-th speaker, 
      // or -1 if not appeared
    vector< vector<string> > statements(nr_speakers_max);
      // statements[i] is the vector of ('A' + i)-th statesments
    for (int i = 0; i < n; i++) {
      getline(cin, line);
      int referrer = line[0] - 'A';
      speakers[referrer] = deduced_speakers[referrer] = 0;
      if (line[3] >= 'A' && line[3] <= 'E') {
        int referred = line[3] - 'A';
        speakers[referred] = deduced_speakers[referred] = 0;
      }
      statements[referrer].push_back(line);
    }
    int deduced_day_or_night = 0;
    deduce_inhabitants(day, 0, speakers, statements, deduced_day_or_night,
      deduced_speakers);
    deduce_inhabitants(night, 0, speakers, statements, deduced_day_or_night,
      deduced_speakers);
    cout << "Conversation #" << c << endl;
    int nr_deduced = 0, nr_facts = 0;
    for (int i = 0; i < nr_speakers_max; i++) {
      int referrer = deduced_speakers[i];
      if (referrer != -1) {
        if (referrer == divine_deduced || referrer == evil_deduced ||
          referrer == human_deduced) {
          nr_facts++; nr_deduced++;
          cout << static_cast<char>(i + 'A') << " is " <<
            ((referrer == divine_deduced) ? "divine.\n" :
            ((referrer == evil_deduced) ? "evil.\n" : "human.\n"));
        }
        else if (referrer)
          nr_deduced++;
      }
    }
    if (deduced_day_or_night) {
      nr_deduced++;
      if (deduced_day_or_night == day_deduced ||
        deduced_day_or_night == night_deduced) {
        nr_facts++;
        cout << "It is " <<
          ((deduced_day_or_night == day_deduced) ? "day.\n" : "night.\n");
      }
    }
    if (!nr_deduced)
      cout << "This is impossible.\n";
    else if (!nr_facts)
      cout << "No facts are deducible.\n";
    cout << endl;
  }
  return 0;
}

No comments:

Post a Comment