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

UVa 193 - Graph Coloring

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

/*
  UVa 193 - Graph Coloring

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

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

void graph_coloring(int n, int ni, const vector< vector<int> >& adjacency_list,
  int nr_black_nodes, vector<bool>& black_nodes,
  int& max_nr_black_nodes, vector<bool>& max_black_nodes)
{
  if (ni == n) {
    if (nr_black_nodes > max_nr_black_nodes) {
      max_nr_black_nodes = nr_black_nodes;
#ifdef DEBUG
      cout << max_nr_black_nodes << endl;
#endif
      for (int i = 0; i < n; i++)
        max_black_nodes[i] = black_nodes[i];
    }
  }
  else if (nr_black_nodes + n - ni <= max_nr_black_nodes)
    return;
  else {
    const vector<int>& al = adjacency_list[ni];
    if (al.empty()) {
      black_nodes[ni] = true; // color ni-th node black
      graph_coloring(n, ni + 1, adjacency_list, nr_black_nodes + 1, black_nodes,
        max_nr_black_nodes, max_black_nodes);
    }
    else {
      size_t i = 0, e = al.size();
      for ( ; i < e; i++)
        if (black_nodes[al[i]])
          break;
      if (i == e) { // all of the connected nodes are white
        black_nodes[ni] = true;
        graph_coloring(n, ni + 1, adjacency_list, nr_black_nodes + 1, black_nodes,
          max_nr_black_nodes, max_black_nodes);
        black_nodes[ni] = false;
      }
      // color ni-th node white
      graph_coloring(n, ni + 1, adjacency_list, nr_black_nodes, black_nodes,
        max_nr_black_nodes, max_black_nodes);
    }
  }
}

int main()
{
  int m;
  cin >> m;
  while (m--) {
    int n, k;
    cin >> n >> k;
    vector< vector<int> > adjacency_list(n, vector<int>()); // adjacency list
    for (int i = 0; i < k; i++) {
      int u, v;
      cin >> u >> v;
      u--; v--;
      adjacency_list[u].push_back(v);
      adjacency_list[v].push_back(u);
    }
    vector<bool> black_nodes(n, false);
      // black_nodes[i] is is true if i-th node is black
    vector<bool> max_black_nodes(n);
    int max_nr_black_nodes = 0;
    graph_coloring(n, 0, adjacency_list, 0, black_nodes,
      max_nr_black_nodes, max_black_nodes);
    cout << max_nr_black_nodes << endl;
    bool first = true;
    for (int i = 0; i < n; i++)
      if (max_black_nodes[i]) {
        if (first)
          first = false;
        else
          cout << ' ';
        cout << i + 1;
      }
    cout << endl;
  }
  return 0;
}

UVa 321 - The New Villa

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

/*
  UVa 321 - The New Villa

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

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

const int nr_rooms_max = 10;
const int room_shift = 1 << nr_rooms_max;
const int lights_mask = room_shift - 1;

bool doors[nr_rooms_max][nr_rooms_max];
  // doors[i][j] is true if there is a door between i-th and j-th rooms
int switches[nr_rooms_max];
  // switches[i] is the bitmap of lights of the i-th room, in which j-th bit of 
  // switches[i] is set if there is a switch for the light of j-th room 
  // in the i-th room

bool visited[nr_rooms_max * room_shift];
  // visited[i] is true if the state of i has already been visited
int parents[nr_rooms_max * room_shift];
  // parents[i] is the i-th parent state

bool push_state(int current, int next, queue<int>& q)
{
  if (!visited[next]) {
    visited[next] = true;
    parents[next] = current;
    q.push(next);
    return true;
  }
  else
    return false;
}

bool bfs(int nr_rooms, int end_state)
{
/*
  Each state consists of two fields:
    bit 0 - bit 9: bitmap of lights where i-th bit is set 
                   if the i-th room's light is on
    bit 10 - bit 13: room index
  Do a breadth-first-search between transferable states.
*/
  queue<int> q;
  int state = 1; // light is on at the first room (hallway)
  visited[state] = true;
  q.push(state);
  while (!q.empty()) {
    int current = q.front();
    q.pop();
    if (current == end_state)
      return true;
    int r = current >> nr_rooms_max, lights = current & lights_mask;
    for (int i = 0, l = 1; i < nr_rooms_max; i++, l <<= 1)
      if (doors[r][i] && lights & l)
        // since i-th rooms has already been lit, we can move to it
        push_state(current, i << nr_rooms_max | lights, q);
    for (int i = 0, l = 1; i < nr_rooms; i++, l <<= 1)
      if (switches[r] & l) { // r-th room has a switch of the light for i-th room
        int next = -1;
        if (lights & l) {
          if (r != i) // the light can be switched to off
            next = r << nr_rooms_max | lights & ~l;
        }
        else // the light can be switched to on
          next = r << nr_rooms_max | lights | l;
        if (next != -1)
          push_state(current, next, q);
      }
  }
  return false;
}

int get_number_of_steps(int end_state)
{
  int nr_steps = 0;
  for (int p = parents[end_state]; p != -1; p = parents[p])
    nr_steps++;
  return nr_steps;
}

void print_steps(int current, int next)
{
  if (current == -1)
    return;
  print_steps(parents[current], current);
  int i = current ^ next;
  if (i & lights_mask) {
    int l = 1;
    for (int j = i >> 1; j; j >>= 1)
      l++;
    if (i & next)
      cout << "- Switch on light in room " << l << ".\n";
    else
      cout << "- Switch off light in room " << l << ".\n";
  }
  else {
    int r = next >> nr_rooms_max;
    cout << "- Move to room " << r + 1 << ".\n";
  }
}

int main()
{
  for (int v = 1; ; v++) {
    int r, d, s;
    cin >> r >> d >> s;
    if (!r && !d && !s)
      break;
    memset(doors, 0, sizeof(doors));
    memset(switches, 0, sizeof(switches));
    for (int i = 0; i < d; i++) {
      int j, k;
      cin >> j >> k;
      j--; k--;
      doors[j][k] = doors[k][j] = true;
    }
    for (int i = 0; i < s; i++) {
      int j, k;
      cin >> j >> k;
      j--; k--;
      switches[j] |= 1 << k;
    }
    memset(visited, 0, sizeof(visited));
    memset(parents, -1, sizeof(parents));
    int end_state = (r - 1) << nr_rooms_max | 1 << (r - 1);
    bool successful = bfs(r, end_state);
    cout << "Villa #" << v << endl;
    if (successful) {
      cout << "The problem can be solved in " <<
        get_number_of_steps(end_state) << " steps:\n";
      print_steps(parents[end_state], end_state);
    }
    else
      cout << "The problem cannot be solved.\n";
    cout << endl;
  }
  return 0;
}

UVa 10181 - 15-Puzzle Problem

Accepted date: 2012-04-30
Ranking (as of 2013-03-23): 145
Language: C++

I used A* search algorithm and for its implementation, I consulted an article of Wikipedia (http://en.wikipedia.org/wiki/A*_search_algorithm).

Some inputs and the corresponding outputs:
3
6 2 8 4
12 14 1 10
13 15 3 9
11 0 5 7
UULDRURDDLLUURRDLURDRULULLDRDRRDLLLURRRULLURDDDR
6 8 4 2
12 14 1 10
13 15 3 9
11 0 5 7
RRULLDLURURRDDLURDLLURUULDLURRRDLLURRDLLLDRRRULDDR
10 1 7 12
5 8 11 2
9 4 3 6
13 14 15 0
LUURULDLDRRULLLURRDDDLLUURRDLLDRRRUUULDRDD

The priority queue implementation (the functions prefixed with "pqueue" and their associated definitions, etc. that are surrounded by the below 'extern "C"' block) is based on the code from https://github.com/vy/libpqueue and is licensed under the Apache 2.0 license:
  Copyright 2010 Volkan Yazici
  Copyright 2006-2010 The Apache Software Foundation


/*
  8.6.2 15-Puzzle Problem
  PC/UVa IDs: 110802/10181, Popularity: B, Success rate: average Level: 3

  To build using Visucal Studio 2008:
    cl -EHsc 15_puzzle_problem.ass.cpp
*/

#include <iostream>
#include <sstream>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <functional>
#include <cstdlib>
#ifdef DEBUG
#include <cassert>
#endif
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;

#ifdef  __cplusplus
extern "C" {
#endif

/** priority data type */
typedef int pqueue_pri_t;

/** callback functions to get/set/compare the priority of an element */
typedef pqueue_pri_t (*pqueue_get_pri_f)(void *a);
typedef void (*pqueue_set_pri_f)(void *a, pqueue_pri_t pri);
typedef int (*pqueue_cmp_pri_f)(pqueue_pri_t next, pqueue_pri_t curr);

/** callback functions to get/set the position of an element */
typedef size_t (*pqueue_get_pos_f)(void *a);
typedef void (*pqueue_set_pos_f)(void *a, size_t pos);

/** debug callback function to print a entry */
typedef void (*pqueue_print_entry_f)(FILE *out, void *a);

/** the priority queue handle */
typedef struct pqueue_t
{
    size_t size;
    size_t avail;
    size_t step;
    pqueue_cmp_pri_f cmppri;
    pqueue_get_pri_f getpri;
    pqueue_set_pri_f setpri;
    pqueue_get_pos_f getpos;
    pqueue_set_pos_f setpos;
    void **d;
} pqueue_t;

#define left(i)   ((i) << 1)
#define right(i)  (((i) << 1) + 1)
#define parent(i) ((i) >> 1)

pqueue_t *
pqueue_init(size_t n,
            pqueue_cmp_pri_f cmppri,
            pqueue_get_pri_f getpri,
            pqueue_set_pri_f setpri,
            pqueue_get_pos_f getpos,
            pqueue_set_pos_f setpos)
{
    pqueue_t *q;

    if (!(q = (pqueue_t *)malloc(sizeof(pqueue_t))))
        return NULL;

    /* Need to allocate n+1 elements since element 0 isn't used. */
    if (!(q->d = (void **)(malloc((n + 1) * sizeof(void *))))) {
        free(q);
        return NULL;
    }

    q->size = 1;
    q->avail = q->step = (n+1);  /* see comment above about n+1 */
    q->cmppri = cmppri;
    q->setpri = setpri;
    q->getpri = getpri;
    q->getpos = getpos;
    q->setpos = setpos;

    return q;
}

void
pqueue_free(pqueue_t *q)
{
    free(q->d);
    free(q);
}

size_t
pqueue_size(pqueue_t *q)
{
    /* queue element 0 exists but doesn't count since it isn't used. */
    return (q->size - 1);
}

static void
bubble_up(pqueue_t *q, size_t i)
{
    size_t parent_node;
    void *moving_node = q->d[i];
    pqueue_pri_t moving_pri = q->getpri(moving_node);

    for (parent_node = parent(i);
         ((i > 1) && q->cmppri(q->getpri(q->d[parent_node]), moving_pri));
         i = parent_node, parent_node = parent(i))
    {
        q->d[i] = q->d[parent_node];
        q->setpos(q->d[i], i);
    }

    q->d[i] = moving_node;
    q->setpos(moving_node, i);
}

static size_t
maxchild(pqueue_t *q, size_t i)
{
    size_t child_node = left(i);

    if (child_node >= q->size)
        return 0;

    if ((child_node+1) < q->size &&
        q->cmppri(q->getpri(q->d[child_node]), q->getpri(q->d[child_node+1])))
        child_node++; /* use right child instead of left */

    return child_node;
}

static void
percolate_down(pqueue_t *q, size_t i)
{
    size_t child_node;
    void *moving_node = q->d[i];
    pqueue_pri_t moving_pri = q->getpri(moving_node);

    while ((child_node = maxchild(q, i)) &&
           q->cmppri(moving_pri, q->getpri(q->d[child_node])))
    {
        q->d[i] = q->d[child_node];
        q->setpos(q->d[i], i);
        i = child_node;
    }

    q->d[i] = moving_node;
    q->setpos(moving_node, i);
}

int
pqueue_insert(pqueue_t *q, void *d)
{
    void *tmp;
    size_t i;
    size_t newsize;

    if (!q) return 1;

    /* allocate more memory if necessary */
    if (q->size >= q->avail) {
        newsize = q->size + q->step;
        if (!(tmp = realloc(q->d, sizeof(void *) * newsize)))
            return 1;
        q->d = (void **)tmp;
        q->avail = newsize;
    }

    /* insert item */
    i = q->size++;
    q->d[i] = d;
    bubble_up(q, i);

    return 0;
}

void
pqueue_change_priority(pqueue_t *q,
                       pqueue_pri_t new_pri,
                       void *d)
{
    size_t posn;
    pqueue_pri_t old_pri = q->getpri(d);

    q->setpri(d, new_pri);
    posn = q->getpos(d);
    if (q->cmppri(old_pri, new_pri))
        bubble_up(q, posn);
    else
        percolate_down(q, posn);
}

void *
pqueue_pop(pqueue_t *q)
{
    void *head;

    if (!q || q->size == 1)
        return NULL;

    head = q->d[1];
    q->d[1] = q->d[--q->size];
    percolate_down(q, 1);

    return head;
}

#ifdef  __cplusplus
}
#endif

/*
  unsigned long long state; // state of a puzzle

  Each state of a puzzle consists of the values stored in the 16 tiles.
  i-th tile (i >= 0) value is stored in the four consecutive bits 
  located between bit (i * 4) and bit (i * 4 + 3).

  If the missing tile is at i-th tile, possible movements are:
    moving up is possible if i > 3.
    moving down is possible if i < 12.
    moving right is possible if (i % 4) < 3.
    movign left is possible if (i % 4) != 0.

  At each step, transfer to the at most four possible states the missing 
  tile can move.

  Further Search is cancelled if it reaches either of the following condition:
    The puzzle gets solved.
    50 steps has passed.
*/

const int nr_tiles = 16; // number of tiles
const int g_score_max = 50; // number of max. steps
const unsigned long long goal = 0x0fedcba987654321ULL;
  // the state of a puzzle when solved

/*
  Solvability of the Tiles Game
  (http://www.cs.bham.ac.uk/~mdr/teaching/modules04/java2/TilesSolvability.html)
*/
bool is_puzzle_solvable(int tiles[])
{
  int ibr, nr_inversions = 0;
  for (int i = 0; i < nr_tiles; i++) {
    if (!tiles[i])
      ibr = i / 4;
    else {
      for (int j = i + 1; j < nr_tiles; j++)
        if (tiles[j] && tiles[i] > tiles[j])
          nr_inversions++;
    }
  }
  return (ibr & 1) ? !(nr_inversions & 1) : (nr_inversions & 1);
}

int heuristic_cost_estimate(unsigned long long state)
{
  int heuristic_cost = 0;
  // for each tile, calcualate the Manhattan distance, i.e., 
  // the distance between the current number of the tile and 
  // the one that the tile should have
  for (int i = 0; i < nr_tiles; i++, state >>= 4) {
    int nr = static_cast<int>(state & 0xf) - 1;
    if (nr >= 0) // not the missing tile
      heuristic_cost += abs(nr / 4 - i / 4) + abs(nr % 4 - i % 4);
/*
    else
      heuristic_cost += (3 - i / 4) + (3 - i % 4);
*/
  }
  return 1.5 * heuristic_cost;
}

struct node
{
  size_t pqueue_pos_; // used internally by libpqueue
  int mi_; // index to the missing tile
  unsigned long long state_; // state of tiles
  int g_score_; // Cost from start along best known path.
  int h_score_; // heuristic_cost_estimate(start, goal)
  int f_score_; // Estimated total cost from start to goal through y.

  node() : pqueue_pos_(-1), mi_(-1), state_(-1), g_score_(-1),
    h_score_(-1), f_score_(-1) {}
  node(int mi, unsigned long long state, int g_score)
    : pqueue_pos_(-1), mi_(mi), state_(state),
    g_score_(g_score), h_score_(heuristic_cost_estimate(state)),
    f_score_(g_score_ + h_score_) {}

  static int get_distance(void* vd);
  static void set_distance(void* vd, int d);
  static int compare_distance(int next, int current);
  static size_t get_position(void* vd);
  static void set_position(void *vd, size_t position);
};

int node::get_distance(void* vd)
{
  return reinterpret_cast<node*>(vd)->f_score_;
}

void node::set_distance(void* vd, int d)
{
  reinterpret_cast<node*>(vd)->f_score_ = d;
}

int node::compare_distance(int next, int current)
{
  return current < next;
}

size_t node::get_position(void* vd)
{
  return reinterpret_cast<node*>(vd)->pqueue_pos_;
}

void node::set_position(void *vd, size_t position)
{
  reinterpret_cast<node*>(vd)->pqueue_pos_ = position;
}

unsigned long long exchange_tile(int i, int j, unsigned long long state)
{
  const unsigned long long mask = 0xfULL;
  unsigned long long nr_i = (state & mask << (i * 4)) >> (i * 4);
  unsigned long long nr_j = (state & mask << (j * 4)) >> (j * 4);
  state &= ~(mask << (i * 4)); state &= ~(mask << (j * 4));
  state |= nr_i << (j * 4); state |= nr_j << (i * 4);
  return state;
}

void add_or_update_node(int mi, int ti, unsigned long long current,
  int g_score, map<unsigned long long, unsigned long long>& came_from,
  pqueue_t* open_set, map<unsigned long long, node*>& in_open_set,
  map<unsigned long long, node*>& removed_from_open_set)
{
  node* pn = NULL;
  int tentative_g_score = g_score + 1;
  unsigned long long neighbor = exchange_tile(mi, ti, current);
    // move the missing tile

  map<unsigned long long, node*>::iterator i;
  if ((i = removed_from_open_set.find(neighbor)) != removed_from_open_set.end())
  {
    // if neighbor has ever been in openset, but currenty it's not in openset
    pn = i->second;
    if (tentative_g_score < pn->g_score_) {
      // neighbor is added only if it has a lesser g_score than 
      // it has ever have at any previous iterations
      pn->g_score_ = tentative_g_score;
      pn->f_score_ = pn->g_score_ + pn->h_score_;
      pqueue_insert(open_set, pn); // add neighbor to openset again
      in_open_set.insert(make_pair(neighbor, pn));
      removed_from_open_set.erase(i);
      came_from[neighbor] = current;
    }
  }
  else if ((i = in_open_set.find(neighbor)) == in_open_set.end()) {
    // else if neighbor has never been in openset
    pn = new node(ti, neighbor, tentative_g_score);
    pqueue_insert(open_set, pn); // add neighbor to openset
    in_open_set.insert(make_pair(neighbor, pn));
    came_from[neighbor] = current;
  }
  else { // neighbor is currently in openset
    pn = i->second;
    if (tentative_g_score < pn->g_score_) {
      pn->g_score_ = tentative_g_score;
      pn->f_score_ = pn->g_score_ + pn->h_score_;
      pqueue_change_priority(open_set, pn->f_score_, pn);
      came_from[neighbor] = current;
    }
  }
}

void free_nodes(const map<unsigned long long, node*>& nodes)
{
  for (map<unsigned long long, node*>::const_iterator i = nodes.begin(),
    e = nodes.end(); i != e; ++i)
    delete i->second;
}

int a_star_seach(int mi, unsigned long long current,
  map<unsigned long long, unsigned long long>& came_from)
{
  const int nr_initial_nodes = 1048576;
  pqueue_t* open_set = pqueue_init(nr_initial_nodes,
    node::compare_distance, node::get_distance, node::set_distance,
    node::get_position, node::set_position);
    // The set of tentative nodes to be evaluated,
    // initially containing the start node.
  map<unsigned long long, node*> in_open_set;
    // key is a state, value is the node instance that is in openset
  map<unsigned long long, node*> removed_from_open_set;
    // key is a state, value is the node instance that has ever been in openset
    // but it's currenty removed form it
  node* pn = new node(mi, current, 0); // start node
  pqueue_insert(open_set, pn);
  in_open_set.insert(make_pair(current, pn));
  came_from[current] = -1;
  int shortest_g_score = -1;
  while (pqueue_size(open_set)) { // while openset is not empty
    pn = reinterpret_cast<node*>(pqueue_pop(open_set));
      // the node in openset having the lowest f_score_ value
    // remove current from openset
    int mi = pn->mi_;
    unsigned long long current = pn->state_;
    int g_score = pn->g_score_;
    in_open_set.erase(current);
    removed_from_open_set.insert(make_pair(current, pn));
    if (current == goal) {
      shortest_g_score = g_score;
      break;
    }
    if (g_score < g_score_max) {
          // for each neighbor in neighbor_nodes(current)
      if (mi < 12) // move the missing tile down
        add_or_update_node(mi, mi + 4, current, g_score, came_from, open_set,
          in_open_set, removed_from_open_set);
      if (mi > 3) // move the missing tile up
        add_or_update_node(mi, mi - 4, current, g_score, came_from, open_set,
          in_open_set, removed_from_open_set);
      if ((mi % 4) < 3) // move the missing tile right
        add_or_update_node(mi, mi + 1, current, g_score, came_from, open_set,
          in_open_set, removed_from_open_set);
      if (mi % 4) // move the missing tile left
        add_or_update_node(mi, mi - 1, current, g_score, came_from, open_set,
          in_open_set, removed_from_open_set);
    }
  }
  pqueue_free(open_set);
  free_nodes(in_open_set);
  free_nodes(removed_from_open_set);
  return shortest_g_score;
}

void print_steps(unsigned long long ps, unsigned long long cs,
  map<unsigned long long, unsigned long long>& states, ostringstream& oss)
{
  if (ps == -1)
    return;
  print_steps(states[ps], ps, states, oss);
  int phi = -1, chi = -1;
  for (int i = 0; phi == -1 || chi == -1; i++, ps >>= 4, cs >>= 4) {
    if (!(ps & 0xf))
      phi = i;
    if (!(cs & 0xf))
      chi = i;
  }
  int ud = chi / 4 - phi / 4;
  if (ud > 0)
    oss << 'D';
  else if (ud < 0)
    oss << 'U';
  else if (chi % 4 - phi % 4 > 0)
    oss << 'R';
  else
    oss << 'L';
}

#ifdef DEBUG
void follow_steps(int mi, unsigned long long state, const string& s)
{
  for (int i = 0; i < s.length(); i++) {
    int nmi;
    switch (s[i]) {
    case 'U':
      assert(mi > 3); nmi = mi - 4; break;
    case 'D':
      assert(mi < 12); nmi = mi + 4; break;
    case 'L':
      assert(mi % 4); nmi = mi - 1; break;
    case 'R':
      assert((mi % 4) < 3); nmi = mi + 1; break;
    }
    state = exchange_tile(mi, nmi, state);
    mi = nmi;
  }
  assert(state == goal);
}
#endif

int main()
{
  int n;
  cin >> n;
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  while (n--) {
    int tiles[nr_tiles];
    unsigned long long current = 0; // puzzle state
    int mi; // index of the missing tile
    for (int i = 0; i < nr_tiles; i++) {
      unsigned long long nr;
      cin >> nr;
      tiles[i] = nr;
      current |= nr << (i * 4);
      if (!nr)
        mi = i;
    }
    int shortest_g_score = -1;
    map<unsigned long long, unsigned long long> came_from;
      // the map of navigated nodes.
    if (is_puzzle_solvable(tiles))
      shortest_g_score = a_star_seach(mi, current, came_from);
    if (shortest_g_score != -1) {
#ifdef DEBUG
      cout << "number of steps = " << shortest_g_score << endl;
#endif
      ostringstream oss;
      print_steps(came_from[goal], goal, came_from, oss);
      cout << oss.str() << endl;
#ifdef DEBUG
      follow_steps(mi, current, oss.str());
#endif
    }
    else
      cout << "This puzzle is not solvable.\n";
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

Saturday, March 23, 2013

UVa 10887 - Concatenation of Languages

Accepted date: 2012-05-04
Ranking (as of 2013-03-23): 109
Language: C++

/*
  UVa 10887 - Concatenation of Languages

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

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

long long convert_to_ll(const string& s)
{
  long long ll = 0;
  for (int i = 0, j = s.length(); i < j; i++)
    ll |= static_cast<long long>(s[i] - 'a' + 1) << (i * 5);
  return ll;
}

pair<long long, long long> concatenate_to_ll(const pair<int, long long>& s,
  const string& t)
{
  long long ll = 0;
  int i = 0, j = min(10 - s.first, static_cast<int>(t.length()));
  for ( ; i < j; i++)
    ll |= static_cast<long long>(t[i] - 'a' + 1) << (i * 5);
  long long hl = 0;
  for (j = 0; i < t.length(); i++, j++)
    hl |= static_cast<long long>(t[i] - 'a' + 1) << (j * 5);
  return make_pair(s.second | (ll << (s.first * 5)), hl);
}

int main()
{
  string s;
  getline(cin, s);
  istringstream iss(s);
  int t;
  iss >> t;
  iss.clear();
  for (int c = 0; c < t; c++) {
    getline(cin, s);
    iss.str(s);
    int m, n;
    iss >> m >> n;
    iss.clear();
    vector< pair<int, long long> > vs(m);
    for (int i = 0; i < m; i++) {
      getline(cin, s);
      vs[i] = make_pair(s.length(), convert_to_ll(s));
    }
    set< pair<long long, long long> > ss;
    for (int i = 0; i < n; i++) {
      getline(cin, s);
      for (int j = 0; j < m; j++)
        ss.insert(concatenate_to_ll(vs[j], s));
    }
    cout << "Case " << c + 1 << ": " << ss.size() << endl;
  }
  return 0;
}

Sunday, March 17, 2013

UVa 10602 - Editor Nottoobad

Accepted date: 2012-05-10
Ranking (as of 2013-03-17): 136
Language: C++

/*
  UVa 10602 - Editor Nottoobad

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

#include <limits>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

const int n_max = 100;

struct word {
  char letters[n_max + 1];
  int common_letters; // number of common letters with the first word
} words[n_max];

bool compare_word(const word& i, const word& j)
{
  if (i.common_letters > j.common_letters)
    return true;
  else if (i.common_letters < j.common_letters)
    return false;
  else
    return strcmp(i.letters + i.common_letters,
      j.letters + j.common_letters) < 0;
}

int main()
{
  int t;
  scanf("%d\n", &t);
  while (t--) {
    int n;
    scanf("%d\n", &n);
    for (int i = 0; i < n; i++)
      gets(words[i].letters);
    for (int i = 1; i < n; i++) {
      const char *p = words[0].letters, *q = words[i].letters;
      for ( ; *p && *q; p++, q++)
        if (*p != *q)
          break;
      words[i].common_letters = p - words[0].letters;
    }
    sort(words + 1, words + n, compare_word);
    int pressed = strlen(words[0].letters);
    for (int i = 1; i < n; i++) {
      const char *p = words[i - 1].letters, *q = words[i].letters;
      for ( ; *p && *q; p++, q++)
        if (*p != *q)
          break;
      pressed += words[i].letters + strlen(words[i].letters) - q;
    }
    printf("%d\n", pressed);
    for (int i = 0; i < n; i++)
      printf("%s\n", words[i].letters);
  }
  return 0;
}

UVa 565 - Pizza Anyone?

Accepted date: 2012-05-20
Ranking (as of 2013-03-17): 34
Language: C++

/*
  UVa 565 - Pizza Anyone?

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

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#ifdef DEBUG
#include <cassert>
#endif
using namespace std;

const int nr_topping_constraints_default = 12;

int nr_topping_constraints,
  nr_topping_constraints_max = nr_topping_constraints_default;

struct topping_constraint {
  int nr_; // number of constraints
  unsigned int constraints_;

  topping_constraint() : nr_(0), constraints_(0) {}
/*
  Each constraint for a topping is represented the consecutive two bits, where 
  the lower bit is for without the topping and the higher bit is for 
  with the topping.
*/
  bool operator<(const topping_constraint& tp) const {return nr_ < tp.nr_;}
};

vector<topping_constraint> topping_constraints(nr_topping_constraints_max);

void parse_topping_constraint(const char* s, topping_constraint& tc)
{
  tc.nr_ = 0; tc.constraints_ = 0;
  do {
    bool with_topping = *s++ == '+';
    int shift = (*s++ - 'A') * 2;
    unsigned int current = (tc.constraints_ >> shift) & 3;
    if (with_topping) {
      if (current == 1) { // without the topping
        tc.nr_--;
        tc.constraints_ &= ~(1 << shift);
      }
      else if (!current) {
        tc.nr_++;
        tc.constraints_ |= 2 << shift;
      }
    }
    else {
      if (current == 2) { // with the topping
        tc.nr_--;
        tc.constraints_ &= ~(2 << shift);
      }
      else if (!current) {
        tc.nr_++;
        tc.constraints_ |= 1 << shift;
      }
    }
  } while (*s != ';');
}

bool accept_constraints(int tci, unsigned int constraints,
  unsigned int& accepted_constraints)
{
  if (tci == nr_topping_constraints) {
    accepted_constraints = constraints;
    return true;
  }
/*
  From topping_constraints[tci], add a topping constraint that is not 
  inconsistent with the constraints that have already been set 
  in constraints
*/
  topping_constraint& tc = topping_constraints[tci];
  unsigned int c = tc.constraints_;
  if (c & constraints)
    // at least one topping constraint has already been satisfied
    return accept_constraints(tci + 1, constraints, accepted_constraints);
  bool successful = false;
  unsigned int mask = 3;
  for (int nr = tc.nr_; nr; mask <<= 2) {
    unsigned int current = constraints & mask, request = c & mask;
    if (request) {
      nr--;
      if (!current) { // a topping constraint has yet not been set
        constraints |= request;
        successful =
          accept_constraints(tci + 1, constraints, accepted_constraints);
        constraints &= ~request;
      }
      if (successful)
        break;
    }
  }
  return successful;
}

void print_toppings(unsigned int constraints)
{
  cout << "Toppings:";
  bool printed = false;
  for (int i = 0; constraints; i++, constraints >>= 2)
    if (constraints & 2) { // with a topping
      if (!printed) {
        printed = true;
        cout << ' ';
      }
      cout << static_cast<char>('A' + i);
    }
  cout << '\n';
}

#ifdef DEBUG
bool verify_constraints(unsigned int constraints)
{
  for (int i = 0; i < nr_topping_constraints; i++) {
    topping_constraint& tc = topping_constraints[i];
    unsigned int c = tc.constraints_;
    unsigned int mask = 3;
    bool satisfied = false;
    for (int nr = tc.nr_; nr; mask <<= 2) {
      unsigned int current = constraints & mask, request = c & mask;
      if (request) {
        nr--;
        if (current == request) {
          satisfied = true; break;
        }
      }
    }
    if (!satisfied)
      return false;
  }
  return true;
}
#endif

int main()
{
  string s;
  while (cin >> s) {
    nr_topping_constraints = 0;
    do {
      if (nr_topping_constraints >= nr_topping_constraints_max) {
        nr_topping_constraints_max++;
        topping_constraints.push_back(topping_constraint());
      }
      parse_topping_constraint(s.c_str(),
        topping_constraints[nr_topping_constraints]);
      nr_topping_constraints++;
      cin >> s;
    } while (s[0] != '.');
    // sort the topping constraints in ascending order of 
    // their number of constraints
    sort(topping_constraints.begin(),
      topping_constraints.begin() + nr_topping_constraints);
    unsigned int accepted_constraints = 0;
    if (accept_constraints(0, 0, accepted_constraints)) {
      print_toppings(accepted_constraints);
#ifdef DEBUG
      assert(verify_constraints(accepted_constraints));
#endif
    }
    else
      cout << "No pizza can satisfy these requests.\n";
  }
  return 0;
}

UVa 387 - A Puzzling Problem

Accepted date: 2012-05-25
Ranking (as of 2013-03-17): 79
Language: C++

/*
  UVa 387 - A Puzzling Problem

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

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

/*
  A piece is represented by 16 bits where 
  i-th bit (0 <= i < 16) is set if there is a solid shape at row of (i / 4) 
  and column of (i % 4).

  Sort the pieces by descending order of the number of solid shapes they have 
  and then backtrack by trying to place a piece at a free area in the square 
  in turn.
*/

const int nr_pieces_max = 5;
const int nr_rows_max = 4, nr_columns_max = 4;

struct piece {
  int nr_;
  int nr_rows_, nr_columns_;
  int nr_solid_shapes_;
  unsigned int shape_;
  bool operator<(const piece& p) const
    {return nr_solid_shapes_ > p.nr_solid_shapes_;}
};

int nr_pieces;
piece pieces[nr_pieces_max];
unsigned long long square;
  // bit (4 * i) - bit (4 * i + 3) is the piece # that is placed at at 
  // row of (i / 4)  and column of (i % 4).

void set_square(int pn, unsigned int shape)
{
  const unsigned long long mask = 0x0f;
  for (int i = 0; i < nr_rows_max * nr_columns_max; i++, shape >>= 1)
    if (shape & 1) {
      square &= ~(mask << (i * 4));
      square |= static_cast<long long>(pn) << (i * 4);
    }
}

void print_square()
{
  for (int i = 0; i < nr_rows_max; i++) {
    for (int j = 0; j < nr_columns_max; j++, square >>= 4)
      cout << static_cast<char>('1' + (square & 0x0f));
    cout << endl;
  }
}

bool form_square(int pi, unsigned int s)
{
  if (pi == nr_pieces)
    return s == 0xffff;
  else {
    piece& p = pieces[pi];
    unsigned int shape = p.shape_;
    for (int i = 0; i <= nr_rows_max - p.nr_rows_; i++, shape <<= 4) {
      // move down a piece
      unsigned int sh = shape;
      for (int j = 0; j <= nr_columns_max - p.nr_columns_; j++, sh <<= 1)
        // move a piece to left
        if (!(s & sh)) { // a piece is placeable
          set_square(p.nr_, sh);
          if (form_square(pi + 1, s | sh))
            return true;
        }
    }
  }
  return false;
}

int main()
{
  for (int nr_puzzles = 0; ; nr_puzzles++) {
    cin >> nr_pieces;
    if (!nr_pieces)
      break;
    if (nr_puzzles)
      cout << endl;
    memset(pieces, 0, sizeof(pieces));
    int nr_shapes = 0;
    for (int i = 0; i < nr_pieces; i++) {
      piece& p = pieces[i];
      p.nr_ = i;
      cin >> p.nr_rows_ >> p.nr_columns_;
      for (int j = 0; j < p.nr_rows_; j++)
        for (int k = 0; k < p.nr_columns_; k++) {
          char s;
          cin >> s;
          if (s == '1') {
            p.nr_solid_shapes_++;
            p.shape_ |= 1 << (j * nr_rows_max + k);
          }
        }
      nr_shapes += p.nr_solid_shapes_;
    }
    bool successful = false;
/*
    if (nr_shapes == nr_rows_max * nr_columns_max) {
*/
      sort(pieces, pieces + nr_pieces);
      square = 0;
      successful = form_square(0, 0);
/*
    }
*/
    if (successful)
      print_square();
    else
      cout << "No solution possible\n";
  }
  return 0;
}

UVa 11100 - The Trip, 2007

Accepted date: 2012-07-10
Ranking (as of 2013-03-16): 152
Language: C++

/*
  UVa 11100 - The Trip, 2007

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

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

const int nr_bags_max = 10000;
int bags[nr_bags_max];

int main()
{
  bool first = true;
  while (true) {
    int n;
    cin >> n;
    if (!n)
      break;
    if (first)
      first = false;
    else
      cout << endl;
    for (int i = 0; i < n; i++)
      cin >> bags[i];
    sort(bags, bags + n);
    int nr_duplicated = 1; // number of duplicated occurences of a same number
    int nr_pieces = 1; // max. number of duplicated occurences of a same number
    for (int i = 1, b = bags[0]; i < n; i++) {
      if (bags[i] == b)
        nr_duplicated++;
      else {
        nr_pieces = max(nr_duplicated, nr_pieces);
        b = bags[i]; nr_duplicated = 1;
      }
    }
    nr_pieces = max(nr_duplicated, nr_pieces);
    vector< vector<int> > packed_bags(nr_pieces);
    for (int i = 0; i < n; i++)
      packed_bags[i % nr_pieces].push_back(bags[i]);
    cout << nr_pieces << endl;
    for (int i = 0; i < nr_pieces; i++) {
      for (int j = 0, je = packed_bags[i].size(); j < je; j++) {
        if (j)
          cout << ' ';
        cout << packed_bags[i][j];
      }
      cout << endl;
    }
  }
  return 0;
}

Saturday, March 16, 2013

UVa 371 - Ackermann Functions

Accepted date: 2012-07-29
Ranking (as of 2013-03-16): 103
Language: C++

/*
  UVa 371 - Ackermann Functions

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

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

const int nr_cache_max = 2097152;
int cache[nr_cache_max]; // cache[i] is the sequence length of i

int sequence_length(int n)
{
  if (n < nr_cache_max && cache[n])
    return cache[n];
  else {
    int length = 0;
    long long m = n;
    while (true) {
      if (m & 1) {
        m *= 3; m++;
      }
      else
        m >>= 1;
      length++;
      if (m == 1)
        break;
      else if (m < nr_cache_max && cache[m]) {
        length += cache[m];
        break;
      }
    }
    if (n < nr_cache_max)
      cache[n] = length;
    return length;
  }
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = -1;
#endif
  while (true) {
    int l, h;
    cin >> l >> h;
#ifdef __ELAPSED_TIME__
    if (start == -1)
      start = clock();
#endif
    if (!l && !h)
      break;
    if (l > h)
      swap(l, h);
    int max_i, max_length = -1;
    for (int i = l; i <= h; i++) {
      int length = sequence_length(i);
      if (length > max_length) {
        max_i = i;
        max_length = length;
      }
    }
    cout << "Between " << l << " and " << h << ", " << max_i <<
      " generates the longest sequence of " << max_length << " values.\n";
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10473 - Simple Base Conversion

Accepted date: 2012-08-05
Ranking (as of 2013-03-16): 265
Language: C++

/*
  UVa 10473 - Simple Base Conversion

  To build using Visucal Studio 2008:
    cl -EHsc -O2 simple_base_conversion.cpp
*/

#include <cstdio>
#include <cstdlib>
using namespace std;

int main()
{
  while (true) {
    char number[16];
    scanf("%s", number);
    if (number[0] == '0' && number[1] == 'x')
      printf("%d\n", strtol(number, NULL, 16));
    else {
      int n = strtol(number, NULL, 10);
      if (n < 0)
        break;
      else
        printf("0x%X\n", n);
    }
  }
  return 0;
}

UVa 10324 - Zeros and Ones

Accepted date: 2012-08-08
Ranking (as of 2013-03-16): 433
Language: C++

/*
  UVa 10324 - Zeros and Ones

  To build using Visucal Studio 2008:
    cl -EHsc -O2 zeros_and_ones.cpp
*/

#include <algorithm>
#include <iterator>
#include <cstdio>
using namespace std;

const int length_max = 1000000;
int positions[length_max];
char zero_ones[length_max];

int main()
{
  int case_nr = 1;
  char c;
  while ((c = getchar()) != EOF && c != '\n') {
    int i = 0, j, n = 0;
    positions[n] = i; zero_ones[n] = c;
    i++; n++;
    while ((c = getchar()) != '\n') {
      if (c != zero_ones[n - 1]) {
        positions[n] = i; zero_ones[n] = c;
        n++;
      }
      i++;
    }
    printf("Case %d:\n", case_nr);
    int nr_queries;
    scanf("%d", &nr_queries);
    for (int q = 0; q < nr_queries; q++) {
      scanf("%d %d", &i, &j);
      if (i > j)
        swap(i, j);
      int pi = distance(positions, lower_bound(positions, positions + n, i));
      if (pi == n || pi < n && positions[pi] > i)
        pi--;
      int pj = distance(positions, lower_bound(positions, positions + n, j));
      if (pj == n || pj < n && positions[pj] > j)
        pj--;
      printf("%s\n", ((pi == pj) ? "Yes" : "No"));
    }
    getchar();
    case_nr++;
  }
  return 0;
}

UVa 10338 - Mischievous Children

Accepted date: 2013-08-16
Ranking (as of 2013-03-16): 97
Language: C++

/*
  UVa 10338 - Mischievous Children

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

#include <cstdio>
#include <cstring>

int main()
{
  const int nr_chars_max = 20;
  long long factorials[nr_chars_max + 1];
  factorials[0] = 1;
  for (int i = 1; i <= nr_chars_max; i++)
    factorials[i] = factorials[i - 1] * i;
#ifdef DEBUG
  printf("%lld\n", factorials[nr_chars_max]);
#endif
  const int nr_letters = 26;
  int frequencies[nr_letters];
    // frequencies[i] is the number of occurrences of (i + 'A')
  int ds;
  scanf("%d", &ds);
  for (int s = 1; s <= ds; s++) {
    memset(frequencies, 0, sizeof(frequencies));
    char word[nr_chars_max + 1];
    scanf("%s", word);
    int length = strlen(word);
    for (int i = 0; i < length; i++)
      frequencies[word[i] - 'A']++;
    long long f = factorials[length];
    for (int i = 0; i < nr_letters; i++)
      if (frequencies[i])
        f /= factorials[frequencies[i]];
    printf("Data set %d: %lld\n", s, f);
  }
  return 0;
}