Saturday, June 8, 2013

UVa 10596 - Morning Walk

Accepted date: 2012-03-26
Ranking (as of 2013-06-08): 442 out of 1173
Language: C++

/*
  UVa 10596 - Morning Walk

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

/*
  This is an Eulerian cycle (or circuit) problem.

  Generate an directed unweighted graph where vertices are intersections and 
  edges are roads.

  An undirected graph has an Eulerian cycle if and only if every vertex has 
  even degree, and all of its vertices with nonzero degree belong to a single 
  connected component.
*/

#include <iostream>
#include <vector>
using namespace std;

bool check_degrees(int n, const vector<int>& degrees)
{
  for (int i = 0; i < n; i++)
    if (degrees[i] & 1) // vetex i has an odd degree
      return false;
  return true;
}

void dfs(int n, int i, const vector< vector<bool> >& graph,
  vector<bool>& visited)
{
  visited[i] = true;
  const vector<bool>& g = graph[i];
  for (int j = 0; j < n; j++)
    if (g[j] && !visited[j])
      dfs(n, j, graph, visited);
}

bool check_connection(int n, const vector<int>& degrees,
  const vector< vector<bool> >& graph)
{
  // do a depth-first-search and see if all of the vertices are connected
  vector<bool> visited(n, false);
  int start;
  for (start = 0; start < n; start++)
    if (degrees[start])
      break;
  if (start < n)
    dfs(n, start, graph, visited);
  for (int i = 0; i < n; i++)
    if (degrees[i]) {
      if (!visited[i])
        return false;
    }
  return true;
}

int main()
{
  int n, r;
  while (cin >> n >> r) {
    vector<int> degrees(n, 0);
    vector< vector<bool> > graph(n, vector<bool>(n, false));
    for (int i = 0; i < r; i++) {
      int c1, c2;
      cin >> c1 >> c2;
      degrees[c1]++;
      degrees[c2]++;
      graph[c1][c2] = graph[c2][c1] = true;
    }
    if (r && check_degrees(n, degrees) && check_connection(n, degrees, graph))
      cout << "Possible\n";
    else
      cout << "Not Possible\n";
  }
  return 0;
}

Saturday, May 25, 2013

UVa 10061 - How many zero's and how many digits ?

Accepted date: 2012-03-03
Ranking (as of 2013-05-25): 217 out of 1024
Language: C++

/*
  UVa 10061 - How many zero's and how many digits ?

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

#include <iostream>
#include <limits>
#include <algorithm>
#include <cmath>
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;

int how_many_zeros(int n, int b)
{
  int nr_occurrences_max = numeric_limits<int>::max();
  for (int i = 2; i <= b; i++) {
    int nr_occurrences_in_b = 0; // number of occurrences of i in b
    for ( ; !(b % i); b /= i)
      nr_occurrences_in_b++;
    if (!nr_occurrences_in_b)
      continue;
    int nr_occurrences_in_f = 0; // number of occurrences of i in n!
    for (int j = i; j <= n; j *= i)
      nr_occurrences_in_f += n / j;
    nr_occurrences_max =
      min(nr_occurrences_max, nr_occurrences_in_f / nr_occurrences_in_b);
  }
  return nr_occurrences_max;
}

int how_many_digits(int n, int b)
{
  double f = 0.0;
  for (int i = 2; i <= n; i++)
    f += log10(static_cast<double>(i));
  f /= log10(static_cast<double>(b));
  return (f != 0.0) ? static_cast<int>(ceil(f + 1.0e-10)) : 1;
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  int n, b;
  while (cin >> n >> b) {
    if (n == 1)
      cout << 0 << ' ' << 1 << endl;
    else
      cout << how_many_zeros(n, b) << ' ' << how_many_digits(n, b) << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 196 - Spreadsheet

Accepted date: 2012-03-28
Ranking (as of 2013-05-25): 130 out of 771
Language: C++

/*
  UVa 196 - Spreadsheet

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

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <cstdlib>
#include <cctype>
using namespace std;

void topologica_sort(int n, vector<int>& in_degrees,
  const vector< vector<int> >& adjacency_list, vector<int>& cells)
{
  queue<int> q;
  for (int i = 0; i < n; i++)
    if (!in_degrees[i])
      q.push(i);
  while (!q.empty()) {
    int i = q.front(); q.pop();
    const vector<int>& al = adjacency_list[i];
    for (size_t j = 0, e = al.size(); j < e; j++) {
      int k = al[j];
      cells[k] += cells[i];
      if (!--in_degrees[k])
        q.push(k);
    }
  }
}

int main()
{
  const int nr_uppers = 'Z' - 'A' + 1;
  int nr_sheets;
  cin >> nr_sheets;
  while (nr_sheets--) {
    int nr_columns, nr_rows;
    cin >> nr_columns >> nr_rows;
    int n = nr_rows * nr_columns;
    vector<int> cells(n, 0);
    vector<int> in_degrees(n, 0);
    vector< vector<int> > adjacency_list(n, vector<int>());
    for (int i = 0; i < nr_rows; i++)
      for (int j = 0; j < nr_columns; j++) {
        int k = i * nr_columns + j;
        string s;
        cin >> s;
        const char* p = s.c_str();
        if (*p == '=') { // formula
          for (p++; *p; ) {
            int c = 0;
            for ( ; isupper(*p); p++) { // get a column number
              c *= nr_uppers;
              c += *p - 'A' + 1;
            }
            int r = 0;
            for ( ; isdigit(*p); p++) { // get a row number
              r *= 10;
              r += *p - '0';
            }
            in_degrees[k]++;
            adjacency_list[(--r) * nr_columns + (--c)].push_back(k);
            if (*p) // '+'
              p++;
          }
        }
        else // number
          cells[k] = atoi(p);
      }
    topologica_sort(n, in_degrees, adjacency_list, cells);
    for (int i = 0; i < nr_rows; i++)
      for (int j = 0; j < nr_columns; j++) {
        int k = i * nr_columns + j;
        cout << cells[k] << ((j == nr_columns - 1) ? '\n' : ' ');
      }
  }
  return 0;
}

UVa 184 - Laser Lines

Accepted date: 2013-04-29
Ranking (as of 2013-05-25): 92 out of 909
Language: C++

/*
  UVa 184 - Laser Lines

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

#include <iostream>
#include <iomanip>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

struct point {
  int x, y;

  bool operator<(const point& p) const;
};

bool point::operator<(const point& p) const
{
  if (x < p.x)
    return true;
  else if (x > p.x)
    return false;
  else
    return y < p.y;
}

bool collinear(const point& p1, const point& p2, const point& p3)
{
  return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) == 0;
}

int main()
{
  while (true) {
    point p;
    cin >> p.x >> p.y;
    if (!p.x && !p.y)
      break;
    vector<point> points;
    points.push_back(p);
    while (true) {
      cin >> p.x >> p.y;
      if (!p.x && !p.y)
        break;
      points.push_back(p);
    }
    sort(points.begin(), points.end());
    bool found = false;
    size_t nr_points = points.size();
    vector< pair<size_t, size_t> > lines;
      // pair of indices that form 'longer' lines
    for (size_t i = 0; i < nr_points - 2; i++)
      for (size_t j = i + 1; j < nr_points - 1; j++) {
        int nr_found = 0;
        for (size_t k = 0; k < lines.size(); k++)
          if (collinear(points[lines[k].first], points[lines[k].second], points[i]) &&
            collinear(points[lines[k].first], points[lines[k].second], points[j])) {
            nr_found = -1; break;
          }
        if (nr_found == -1)
          continue;

        for (size_t k = j + 1; k < nr_points; k++) {
          if (collinear(points[i], points[j], points[k])) {
            if (!found) {
              found = true;
              cout << "The following lines were found:\n";
            }
            if (!nr_found)
              cout << setfill(' ') << '(' <<
                setw(4) << points[i].x << ',' <<
                setw(4) << points[i].y << ')' <<
                '(' << setw(4) << points[j].x << ',' <<
                setw(4) << points[j].y << ')';
            cout << '(' << setw(4) << points[k].x <<
              ',' << setw(4) << points[k].y << ')';
            nr_found++;
          }
        }
        if (nr_found) {
          cout << endl;
          if (nr_found > 1)
            lines.push_back(make_pair(i, j));
        }
      }
    if (!found)
      cout <<"No lines were found\n";
  }
  return 0;
}

Thursday, March 28, 2013

UVa 448 - OOPS!

Accepted date: 2013-03-27
Ranking (as of 2013-03-28): 34
Language: C++

/*
  UVa 448 - OOPS!

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

#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;

const char* opcodes[] = {
  "ADD", "SUB", "MUL", "DIV", "MOV", "BREQ", "BRLE", "BRLS",
  "BRGE", "BRGR", "BRNE", "BR", "AND", "OR", "XOR", "NOT"
};

const int nr_operand_digits = 4;
const int nr_digits_max = 30 + nr_operand_digits - 1;
int idigits, nr_digits;
char digits[nr_digits_max + 1];

int get_opcode()
{
  if (idigits == nr_digits) {
    if (!gets(digits))
      return -1;
    idigits = 0;
    nr_digits = strlen(digits);
  }
  char c = digits[idigits++];
  if (isdigit(c))
    return c - '0';
  else
    return c - 'A' + 10;
}

int get_operand()
{
  if (idigits + nr_operand_digits > nr_digits) {
    memcpy(digits, digits + idigits, nr_digits - idigits);
    gets(digits + nr_digits - idigits);
    idigits = 0;
    nr_digits = strlen(digits);
  }
  int opr = 0;
  for (int i = 0; i < nr_operand_digits; i++, idigits++) {
    if (i)
      opr <<= 4;
    char c = digits[idigits];
    if (isdigit(c))
      opr += c - '0';
    else
      opr += c - 'A' + 10;
  }
  return opr;
}

void print_operand(int opr)
{
  int mode = (opr & 0xe000) >> 14, value = opr & 0x3fff;
  switch (mode) {
  case 0:
    printf("R%d", value); break;
  case 1:
    printf("$%d", value); break;
  case 2:
    printf("PC+%d", value); break;
  case 3:
    printf("%d", value); break;
  }
}

int main()
{
  int opc;
  while ((opc = get_opcode()) != -1) {
    printf("%s ", opcodes[opc]);
    print_operand(get_operand());
    if (opc <= 4 || opc >= 12 && opc <= 14) {
      putchar(',');
      print_operand(get_operand());
      if (opc >= 12 && opc <= 14) {
        putchar(',');
        print_operand(get_operand());
      }
    }
    putchar('\n');
  }
  return 0;
}

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;
}

UVa 165 - Stamps

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

/*
  UVa 165 - Stamps

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

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;

void attain_stamp(int h, int k, const vector<int>& stamps,
  int si /* index to stamps */,  int nr_attained, int attained_sum,
  vector<bool>& attainables)
{
  if (nr_attained == h || si == k) {
    if (attained_sum)
      attainables[attained_sum - 1] = true;
  }
  else {
    for (int i = 0; i <= h - nr_attained; i++)
      attain_stamp(h, k, stamps, si + 1,
        nr_attained + i, attained_sum + stamps[si] * i, attainables);
  }
}

bool attain_stamp(int h, int k, vector<int>& stamps,
  int si /* index to stamps */, int& max_attainable, vector<int>& max_stamps)
{
  if (si == k) {
    vector<bool> attainables(stamps[k - 1] * h, false);
      // attainables[i] is true if (i - 1) is attainable
    attain_stamp(h, k, stamps, 0,  0, 0, attainables);
    int i;
    for (i = 0; i < stamps[k - 1] * h; i++)
      if (!attainables[i])
        break;
    if (i < stamps[k - 1])
      return false;
    else {
#ifdef DEBUG
      for (int j = 0; j < k; j++)
        cout << setfill(' ') << setw(3) << stamps[j];
      cout << " ->" << setfill(' ') <<
        setw(3) << i << endl;
#endif
      if (i > max_attainable) {
        max_attainable = i;
        for (int j = 0; j < k; j++)
          max_stamps[j] = stamps[j];
      }
      return true;
    }
  }
  else {
    int s = stamps[si - 1] + 1;
    for (stamps[si] = s; ; stamps[si]++)
      if (!attain_stamp(h, k, stamps, si + 1, max_attainable, max_stamps))
        break;
    if (stamps[si] == s)
      return false;
    else {
      stamps[si] = s;
      return true;
    }
  }
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = -1;
#endif
  while (true) {
    int h, k;
    cin >> h >> k;
#ifdef __ELAPSED_TIME__
    if (start == -1)
      start = clock();
#endif
    if (!h && !k)
      break;
    vector<int> stamps(k), max_stamps(k);
    for (int i = 0; i < k; i++)
      stamps[i] = max_stamps[i] = i + 1;
    int max_attainable = h;
    attain_stamp(h, k, stamps, 1, max_attainable, max_stamps);
    for (int i = 0; i < k; i++)
      cout << setfill(' ') << setw(3) << max_stamps[i];
    cout << " ->" << setfill(' ') <<
      setw(3) << max_attainable << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}