Saturday, June 29, 2013

UVa 213 - Message Decoding

Accepted date: 2013-06-29
Ranking (as of 2013-06-29): 35 out of 870
Language: C++

/*
  UVa 213 - Message Decoding

  To build using Visucal Studio 2010:
    cl -EHsc UVa_213_Message_Decoding.cpp
*/

#include <cstdio>

int read_digits(int n)
{
  int d = 0, c;
  while (n--) {
    d <<= 1;
    while ((c = getchar()) == '\n')
      ;
    d += c - '0';
  }
  return d;
}

int main()
{
  char chars_map[1 + 3 + 7 + 15 + 31 + 63 + 127];
  const int chars_map_indices[] = {-1, 0, 1, 4, 11, 26, 57, 120};
    // chars_map_indices[i] is the index to chars_map[] for the key length of i
  const int terminaters[] = {0, 1, 3, 7, 15, 31, 63, 127};
    // terminaters[i] is the terminater for the key length of i
  while (true) {
    int c = getchar();
    if (c == EOF)
      break;
    else if (c == '\n')
      continue;
    // read a header
    char* p = chars_map;
    do
      *p++ = static_cast<char>(c);
    while ((c = getchar()) != '\n');
    int length;
    while (length = read_digits(3)) {
      char* q = &chars_map[chars_map_indices[length]];
      int i, t = terminaters[length];
      while ((i = read_digits(length)) != t)
        putchar(*(q + i));
    }
    putchar('\n');
  }
  return 0;
}

UVa 10364 - Square

Accepted date: 2013-06-29
Ranking (as of 2013-06-29): 139 out of 949
Language: C++

Applied backtrack.


/*
  UVa 10364 - Square

  To build using Visual Studio 2010:
    cl -EHsc -O2 UVa_10364_Square.cpp
*/

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

const int ns_max = 20;
struct stick {
  bool used_;
  int length_;
  bool operator<(const stick& s) const {return length_ > s.length_;}
} sticks[ns_max];

bool form_square(int n /* number of sticks */, int i /* index to sticks[] */,
  int nrs /* number of remaining sides */,
  int sl /* side length */, int rsl /* remaining side length */)
{
  if (!rsl) {
    if (!--nrs)
      return true;
    else
      return form_square(n, 0, nrs, sl, sl);
  }
  else {
    for (int j = i; j < n; j++)
      if (sticks[j].length_ <= rsl && !sticks[j].used_) {
        sticks[j].used_ = true;
        if (form_square(n, j + 1, nrs, sl, rsl - sticks[j].length_))
          return true;
        sticks[j].used_ = false;
      }
    return false;
  }
}

int main()
{
  int t;
  cin >> t;
  while (t--) {
    int n;
    cin >> n;
    int s = 0;
    for (int i = 0; i < n; i++) {
      sticks[i].used_ = false;
      cin >> sticks[i].length_;
      s += sticks[i].length_;
    }
    int sl = s / 4;
    bool yes = true;
    if (sl * 4 != s)
      yes = false;
    else {
      for (int i = 0; i < n; i++)
        if (sticks[i].length_ > sl) {
          yes = false; break;
        }
      if (yes) {
        sort(sticks, sticks + n); // sort in descending order of lengths
        yes = form_square(n, 0, 4, sl, sl);
      }
    }
    cout << ((yes) ? "yes\n" : "no\n");
  }
  return 0;
}

Saturday, June 15, 2013

UVa 571 - Jugs

Accepted date: 2011-12-20
Ranking (as of 2013-06-15): 670 out of 1520
Language: C++

/*
  UVa 571 - Jugs

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

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

enum {fill_A, fill_B, empty_A, empty_B, pour_A_B, pour_B_A};

struct jugs {
  int a_, b_;
  stack<char> steps_;

  jugs(int a, int b, char s) : a_(a), b_(b) {steps_.push(s);}
  jugs(int a, int b, char s, const stack<char>& steps) : a_(a), b_(b),
    steps_(steps) {steps_.push(s);}
};

void print_steps(stack<char>& steps)
{
  const char* instructions[] = {"fill A\n", "fill B\n",
    "empty A\n", "empty B\n", "pour A B\n", "pour B A\n"};
  if (!steps.empty()) {
    char s = steps.top(); steps.pop();
    print_steps(steps);
    cout << instructions[s];
  }
}

bool push_jugs_state(int a, int b, char s, const stack<char>& steps,
  vector< vector<bool> >& states, queue<jugs>& q)
{
  if (!states[a][b]) {
    states[a][b] = true;
    q.push(jugs(a, b, s, steps));
    return true;
  }
  else
    return false;
      // do not transfer to the state that has already been transferred before
}

void pour_jugs(int ca, int cb, int n)
{
  vector< vector<bool> > states(ca + 1, vector<bool>(cb + 1, false));
    // states[i][j] is true if the state where the content of A is i and 
    // the content of B is j has already been examined
  queue<jugs> q;
  if (ca > n) {
    states[ca][0] = true;
    q.push(jugs(ca, 0, fill_A));
  }
  else {
    states[0][cb] = true;
    q.push(jugs(0, cb, fill_B));
  }
  for ( ; !q.empty(); q.pop()) {
    jugs& j = q.front();
    if (j.b_ == n) {
      print_steps(j.steps_);
      break;
    }
    int a, b, p;
    // if either of the jugs is empty, try pouring to the empty jug, 
    // or fill the empty jug
    if (!j.a_) {
      p = min(ca, j.b_);
      push_jugs_state(p, j.b_ - p, pour_B_A, j.steps_, states, q);
      if (j.b_ < cb)
        push_jugs_state(ca, j.b_, fill_A, j.steps_, states, q);
    }
    else if (!j.b_) {
      p = min(j.a_, cb);
      push_jugs_state(j.a_ - p, p, pour_A_B, j.steps_, states, q);
      if (j.a_ < ca)
        push_jugs_state(j.a_, cb, fill_B, j.steps_, states, q);
    }
    // if both of the jugs are not empty, try pouring between jags, 
    // or empty the fully-filled jug
    else {
      if (j.a_ < ca) {
        p = min(ca - j.a_, j.b_);
        push_jugs_state(j.a_ + p, j.b_ - p, pour_B_A, j.steps_, states, q);
      }
      else if (j.a_ == ca)
        push_jugs_state(0, j.b_, empty_A, j.steps_, states, q);
      if (j.b_ < cb) {
        p = min(cb - j.b_, j.a_);
        push_jugs_state(j.a_ - p, j.b_ + p, pour_A_B, j.steps_, states, q);
      }
      else if (cb == j.b_)
        push_jugs_state(j.a_, 0, empty_B, j.steps_, states, q);
    }
  }
  cout << "success\n";
}

int main()
{
  int ca, cb, n;
  while (cin >> ca >> cb >> n)
    pour_jugs(ca, cb, n);
  return 0;
}

Uva 11029 - Leading and Trailing

Accepted date: 2011-12-24
Ranking (as of 2013-06-15): 242 out of 513
Language: C++

/*
  Uva 11029 - Leading and Trailing

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

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

int leading(int n, int k)
{
/*
  n^k = 10^(k * logn)
  decimal part of n^k = 10^(decimal part of k * log(n))
*/
  double k_log_n = static_cast<double>(k) * log10(static_cast<double>(n));
  double decimal_part_of_k_log_n = k_log_n - floor(k_log_n);
  double decimal_part = pow(10.0, decimal_part_of_k_log_n);
  return static_cast<int>(decimal_part * 100.0);
}

long long trailing(int n, int k)
{
  if (!k)
    return 1;
  long long t = trailing(n, k / 2);
  t = (t * t) % 1000;
  if (k & 1) // k is odd
    t = (t * n) % 1000;
  return t;
}

int main()
{
  int nr_cases;
  cin >> nr_cases;
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  while (nr_cases--) {
    int n, k;
    cin >> n >> k;
    cout << leading(n, k) << "..." <<
      setfill('0') << setw(3) << trailing(n, k) << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

Uva 10023 - Square root

Accepted date: 2011-12-25
Ranking (as of 2013-06-15): 408 out of 875
Language: JAVA

// Uva 10023 - Square root

/*
  See Methods of computing square roots - Wikipedia, the free encyclopedia.
    (http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Digit-by-digit_calculation)
*/

import java.util.Scanner;
import java.math.BigInteger;

class Main {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    String line = sc.nextLine();
    int nr_cases = Integer.parseInt(line);
    while (nr_cases-- > 0) {
      sc.nextLine(); // skip a line
      line = sc.nextLine();
      System.out.println(squareRoot(line.trim()));
      if (nr_cases > 0)
        System.out.println();
    }
  }

  static String squareRoot(String n) {
    final BigInteger TWENTY = BigInteger.TEN.add(BigInteger.TEN);
    int i = 0;
    BigInteger c = BigInteger.valueOf(n.charAt(i++) - '0'); // current value
    if ((n.length() & 1) == 0)
      c =
        c.multiply(BigInteger.TEN).add(BigInteger.valueOf(n.charAt(i++) - '0'));
    BigInteger p = BigInteger.ZERO; // part of the root found so far
    while (true) {
      // determine the greatest digit x such that y = (20 * p + x) * x 
      // does not exceed c
      BigInteger x = BigInteger.ZERO, y = BigInteger.ZERO;
      if (p.equals(BigInteger.ZERO)) {
        if (!c.equals(BigInteger.ZERO)) {
          x = BigInteger.valueOf((long)Math.sqrt(c.doubleValue()));
            // x = floor(sqrt(c))
          y = x.multiply(x); // y = x * x
        }
      }
      else {
        BigInteger twenty_p = p.multiply(TWENTY);
        x = c.divide(twenty_p); // c / (20 * p)
        y = twenty_p.add(x).multiply(x); // (20 * p + x) * x
        int result = y.compareTo(c);
        if (result < 0) {
          for (x = x.add(BigInteger.ONE); ; x = x.add(BigInteger.ONE)) {
            y = twenty_p.add(x).multiply(x);
            if (y.compareTo(c) > 0)
              break;
          }
          x = x.subtract(BigInteger.ONE);
          y = twenty_p.add(x).multiply(x);
        }
        else if (result > 0) {
          for (x = x.subtract(BigInteger.ONE);
            ; x = x.subtract(BigInteger.ONE)) {
            y = twenty_p.add(x).multiply(x);
            if (y.compareTo(c) <= 0)
              break;
          }
        }
      }
      c = c.subtract(y);
      p = p.multiply(BigInteger.TEN).add(x);
//      System.out.println(String.format("%s %s", p, c));
      if (i == n.length())
        break;
      c =
        c.multiply(BigInteger.TEN).add(BigInteger.valueOf(n.charAt(i++) - '0'));
      c =
        c.multiply(BigInteger.TEN).add(BigInteger.valueOf(n.charAt(i++) - '0'));
    }
    return p.toString();
  }
}

UVa 10308 - Roads in the North

Accepted date: 2011-12-28
Ranking (as of 2013-06-15): 211 out of 742
Language: C++

/*
  UVa 10308 - Roads in the North

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

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

const int nr_villages_max = 10000;

vector< vector< pair<int, int> > > roads(nr_villages_max + 1);
  // roads[i].first is the number of village adjacent to the village i
  // roads[i].second is the length of road between the village i and 
  // roads[i].first

int dfs(int v, int pv, int& diameter)
{
  int max_d = 0, second_max_d = 0;
  for (vector< pair<int, int> >::const_iterator i = roads[v].begin(),
    e = roads[v].end(); i != e; ++i) {
    if (i->first == pv)
      continue;
    int d = i->second + dfs(i->first, v, diameter);
    if (d > max_d) {
      second_max_d = max_d; max_d = d;
    }
    else if (d > second_max_d)
      second_max_d = d;
  }
  diameter = max(diameter, max_d + second_max_d);
  return max_d;
}

int main()
{
  int nr_villages = 0;
  string line;
  do {
    getline(cin, line);
    if (!cin.eof() && !line.empty()) {
      istringstream iss(line);
      int vi, vj, l;
      iss >> vi >> vj >> l;
      if (vi > nr_villages || vj > nr_villages) {
        int i = max(vi, vj);
        for (int j = nr_villages + 1; j <= i; j++)
          roads[j].clear();
        nr_villages = i;
      }
      roads[vi].push_back(make_pair(vj, l));
      roads[vj].push_back(make_pair(vi, l));
    }
    else if (nr_villages) { // end of a set of input
      int diameter = 0;
      // calculate the diameter (or longest path) of a tree, 
      // using depth-first search
      dfs(1, 0, diameter);
      cout << diameter << endl;
      nr_villages = 0;
    }
    else if (!cin.eof()) // no input lines
      cout << 0 << endl;
  } while (!cin.eof());
  return 0;
}

UVa 10375 - Choose and divide

Accepted date: 2012-01-02
Ranking (as of 2013-06-15): 141 out of 976
Language: C++

/*
  UVa 10375 - Choose and divide

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

#include <iostream>
#include <utility>
#include <algorithm>
#include <limits>
#include <cstdio>
using namespace std;

/*
  C(p, q) / C(r, s) = (p! * s! * (r - s)!) / (q! * r! * (p - q)!)
*/

const int nr_facts = 3; // number of factorials

bool multiply_by_partial_factorial(pair<int, int>& pfact, double result_max,
  double& result)
{
  int i;
  for (i = pfact.first; i <= pfact.second; ) {
    result *= static_cast<double>(i++);
    if (result > result_max)
      break;
  }
  pfact.first = i;
  return pfact.first > pfact.second;
}

bool divide_by_partial_factorial(pair<int, int>& pfact, double result_min,
  double& result)
{
  int i;
  for (i = pfact.first; i <= pfact.second; ) {
    result /= static_cast<double>(i++);
    if (result < result_min)
      break;
  }
  pfact.first = i;
  return pfact.first > pfact.second;
}

int main()
{
  int p, q, r, s;
  while (cin >> p >> q >> r >> s) {
    int dvd_facts[nr_facts] = {p, s, r - s}, // dividend factorials
      dvs_facts[nr_facts] = {q, r, p - q}; // divisor factorials
    sort(dvd_facts, dvd_facts + nr_facts);
    sort(dvs_facts, dvs_facts + nr_facts);
    int i, j, nr_dvd_pfacts = 0, nr_dvs_pfacts = 0;
    pair<int, int> dvd_pfacts[nr_facts], dvs_pfacts[nr_facts];
      // dividend/divisor partial factorials
    for (i = 0; i < nr_facts; i++) {
      if (dvd_facts[i] > dvs_facts[i])
        dvd_pfacts[nr_dvd_pfacts++] = make_pair(dvs_facts[i] + 1, dvd_facts[i]);
      else if (dvd_facts[i] < dvs_facts[i])
        dvs_pfacts[nr_dvs_pfacts++] = make_pair(dvd_facts[i] + 1, dvs_facts[i]);
    }
    i = j = 0;
    double result = 1.0;
    const double result_min =
      numeric_limits<float>::min(), result_max = numeric_limits<float>::max();
    do {
      if (i < nr_dvd_pfacts &&
        multiply_by_partial_factorial(dvd_pfacts[i], result_max, result))
        i++;
      if (j < nr_dvs_pfacts &&
        divide_by_partial_factorial(dvs_pfacts[j], result_min, result))
        j++;
    } while (i < nr_dvd_pfacts || j < nr_dvs_pfacts);
    printf("%.5lf\n", result);
  }
  return 0;
}

Uva 11027 - Palindromic Permutation

Accepted date: 2012-01-04
Ranking (as of 2013-06-15): 189 out of 281
Language: C++

/*
  Uva 11027 - Palindromic Permutation

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

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

/*
  Count the number of occurrences of each lowercase letter in a given string:
    For a string of even length, all of the number of occurrences should be even.
    For a string of odd length, all but one of the number of occurrences should 
      be even.
  Take the half of the letters from the string and generate permutation.
*/

const int nr_letters = 26; // number of lowercase letters
const int length_max = 30;
long long factorials[length_max / 2 + 1]; // factorials[i] is i!

void generate_factorials()
{
  factorials[0] = 1;
  for (int i = 1; i <= length_max / 2; i++)
    factorials[i] = factorials[i - 1] * i;
}

int get_half_palindrome(const char* s,
  int half_palindrome_letters[], char half_palindrome[])
{
  int length = 0;
  for ( ; *s; s++, length++)
    half_palindrome_letters[*s - 'a']++;
  int i_odd_letter = -1;
    // index of the letter that has an odd number of occurrences
  for (int i = 0; i < nr_letters; i++) {
    if (half_palindrome_letters[i] & 1) {
      if (!(length & 1) || i_odd_letter != -1)
        return -1;
      i_odd_letter = i;
    }
    half_palindrome_letters[i] >>= 1;
  }
  int half_palindrome_length = 0;
  // append the letters half the numbers of original strings 
  // in alphabetical order
  for (int i = 0; i < nr_letters; i++)
    if (half_palindrome_letters[i]) {
      for (int j = half_palindrome_letters[i]; j; j--)
        half_palindrome[half_palindrome_length++] = 'a' + i;
    }
  // append the letter that has an odd number of occurrences
  if (i_odd_letter != -1)
    half_palindrome[half_palindrome_length++] = 'a' + i_odd_letter;
  half_palindrome[half_palindrome_length] = '\0';
  return half_palindrome_length;
}

int generate_n_th_palindrome(long long n, int length,
  int letters[], char palindrome[])
{
/*
  For the number of permutations of words, see 
    "Multinomial theorem - Wikipedia, the free encyclopedia":
  ... the multinomial coefficient is also the number of distinct ways to 
  permute a multiset of n elements, and k(i) are the multiplicities of each of 
  the distinct elements. ...
*/
  int i, j;
  long long numerator = factorials[length], denominator = 1;
  for (i = 0; i < nr_letters; i++)
    if (letters[i])
      denominator *= factorials[letters[i]];
  if (n > numerator / denominator)
    return -1;
  for (i = 0; i < length; i++) {
    numerator /= length - i;
    for (j = i; j < length; ) {
      char c = palindrome[j];
      int k = letters[c - 'a'];
      long long p = numerator / (denominator / k);
      if (n <= p) {
        denominator /= k;
        letters[c - 'a']--;
        // insert c at palindrome[i]
        memmove(&palindrome[i + 1], &palindrome[i], sizeof(char) * (j - i));
        palindrome[i] = c;
        break;
      }
      n -= p; j += k;
    }
  }
  return length;
}

int get_n_th_palindrome(int n, int palindrome_length, int half_palindrome_length,
  int half_palindrome_letters[], char half_palindrome[], char palindrome[])
{
  int permutation_length = palindrome_length - half_palindrome_length;
  if (generate_n_th_palindrome(n, permutation_length,
    half_palindrome_letters, half_palindrome) == -1)
    return -1;
  // generate the n-th palindrome
  memcpy(palindrome, half_palindrome, half_palindrome_length);
  for (int i = 0, j = palindrome_length - 1; i < permutation_length; i++, j--)
    palindrome[j] = palindrome[i];
  palindrome[palindrome_length] = '\0';
  return palindrome_length;
}

int main()
{
  generate_factorials();
  int nr_cases;
  scanf("%d", &nr_cases);
  for (int c = 1; c <= nr_cases; c++) {
    char s[length_max + 1];
    int n;
    scanf("%s %d", s, &n);
    printf("Case %d: ", c);
    char half_palindrome[length_max / 2 + 1], palindrome[length_max + 1];
    int half_palindrome_letters[nr_letters];
      // half_palindrome_letters[i] is the number of occurrences of 
      // letter ('a' + i) in the half_palindrome
    memset(half_palindrome_letters, 0, sizeof(half_palindrome_letters));
    int half_palindrome_length =
      get_half_palindrome(s, half_palindrome_letters, half_palindrome);
    int palindrome_length = (half_palindrome_length > 0) ?
      get_n_th_palindrome(n, strlen(s),
        half_palindrome_length, half_palindrome_letters,
        half_palindrome, palindrome) : -1;
    printf("%s\n", ((palindrome_length > 0) ? palindrome : "XXX"));
  }
  return 0;
}

UVa 10759 - Dice Throwing

Accepted date: 2012-01-07
Ranking (as of 2013-06-15): 248 out of 604
Language: C++

/*
  UVa 10759 - Dice Throwing

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

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

const int n_max = 24, x_max = 150;
long long dice_throwings[n_max + 1][x_max + 1]; // cache
  // dice_throwings[n][x] is the number of cases in which the sum of all thrown 
  // dice is less than x when n dice are thrown

void intialize_cache()
{
  for (int i = 0; i <= n_max; i++)
    for (int j = 0; j <= x_max; j++)
      dice_throwings[i][j] = -1;
  dice_throwings[1][0] = 0;
  for (int j = 1; j <= 6; j++)
    dice_throwings[1][j] = j - 1;
  for (int j = 7; j <= x_max; j++)
    dice_throwings[1][j] = 6;
}

long long dice_throwing(int n, int x)
// return the number of cases in which the sum of all thrown dice is less than x 
// when n dice are thrown
{
  if (dice_throwings[n][x] != -1)
    return dice_throwings[n][x];
  else {
    long long nr_cases = 0;
    for (int i = 1, j = min(x, 6); i <= j; i++)
      nr_cases += dice_throwing(n - 1, x - i);
    dice_throwings[n][x] = nr_cases;
    return nr_cases;
  }
}

long long calculate_gcd(long long a, long long b)
{
  if (a < b)
    return calculate_gcd(b, a);
  if (!b)
    return a;
  else
    return calculate_gcd(b, a % b);
}

int main()
{
  intialize_cache();
  while (true) {
    int n, x;
    cin >> n >> x;
    if (!n && !x)
      break;
    long long denominator = static_cast<long long>(
      pow(6.0, static_cast<double>(n)));
    long long numerator = denominator - dice_throwing(n, x);
    if (numerator) {
      long long gcd = calculate_gcd(numerator, denominator);
      numerator /= gcd; denominator /= gcd;
    }
    if (!numerator)
      cout << 0 << endl;
    else if (denominator == 1)
      cout << 1 << endl;
    else
      cout << numerator << '/' << denominator << endl;
  }
  return 0;
}

UVa 10277 - Boastin' Red Socks

Accepted date: 2012-01-12
Ranking (as of 2013-06-15): 43 out of 311
Language: C++

/*
  UVa 10277 - Boastin' Red Socks

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

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

/*
  Let r be the number of red socks and s be the number of all socks, then:
    C(r, 2) / C(s, 2) = p / q.
    r * (r - 1) = k * p, s * (s -  1) = k * q.
*/

long long calculate_gcd(long long a, long long b)
{
  if (a < b)
    return calculate_gcd(b, a);
  if (!b)
    return a;
  else
    return calculate_gcd(b, a % b);
}

long long solve_quadratic_equation(long long n, long long n_max)
{
  long long i =
    static_cast<long long>((1.0 + sqrt(1.0 + 4.0 * static_cast<double>(n))) /
    2.0);
  return (i <= n_max && i * i - i - n == 0) ? i : - 1;
}

int main()
{
  const long long nr_socks_max = 50000;
  while (true) {
    long long p, q;
    cin >> p >> q;
    if (!p && !q)
      break;
    long long r = -1, s;
    if (!p) {
      r = 0; s = 2; // just a couple of black socks
    }
    else if (p == q)
      r = s = 2; // just a couple of red socks
    else {
      long long gcd = calculate_gcd(p, q);
      p /= gcd; q /= gcd;
      for (s = 3; s <= nr_socks_max; s++) {
        long long t = s * (s - 1);
        if (!(t % q)) {
          long long k = t / q;
          if ((r = solve_quadratic_equation(k * p, s)) != -1)
            break;
        }
      }
    }
    if (r != -1)
      cout << r << ' ' << s - r << endl;
    else
      cout << "impossible\n";
  }
  return 0;
}

UVa 10169 - Urn-ball Probabilities !

Accepted date: 2012-01-13
Ranking (as of 2013-06-15): 68 out of 322
Language: C++

/*
  UVa 10169 - Urn-ball Probabilities !

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

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

const int n_max = 1000000;
double p[n_max + 1];
  // p[i] is the probability that you have not picked up two red balls 
  // in all of your pick-ups in i pick-ups
double q[n_max + 1];
  // q[i] is number of zeros in probability 
  // that all of your pick ups has both balls as red in i pick-ups

int main()
{
  p[0] = 1.0; q[0] = 0.0;
  for (int i = 1; i <= n_max; i++) {
    double d = static_cast<double>(i);
    p[i] = p[i - 1] * (d * (d + 1.0) - 1.0) / (d * (d + 1.0));
    q[i] = q[i - 1] - log10(1.0 / (d * (d + 1.0)));
  }
  int n;
  while (cin >> n)
    printf("%.6lf %d\n", 1.0 - p[n], static_cast<int>(q[n]));
  return 0;
}

UVa 11181 - Probability|Given

Accepted date: 2012-01-16
Ranking (as of 2013-06-15): 33 out of 349
Language: C++

/*
  UVa 11181 - Probability|Given

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

/*
  For example - first test case... 
  3 people, 2 of this person buy something. 
  There are only C(3,2) = 3 possibilities: 
    a) 1 & 2 buy something, 3 not, probability of this is 0,1 * 0,2 * 0,7 = 0,014
    b) 1 & 3 buy something, 2 not, probability of this is 0,1 * 0,8 * 0,3 = 0,024
    c) 2 & 3 buy something, 1 not, probability of this is 0,9 * 0,2 * 0,3 = 0,054

  The total probability of this three events is 0,014 + 0,024 + 0,054 = 0,092. 

  Let's determine probability, that person 1 buy something. 
  This is true in cases a) and b). Also (0,014 + 0,024) /0,092 = 0,413043478 
  For person 2 -> in cases a) and c) person 2 buy something.
    Also (0,014+0,054)/0,092 = 0,739130434 
  For person 3 -> in cases b) and c) person 3 buy something.
    Also (0,024+0,054)/0,092 = 0,847826087 
*/

/*
  Let p[i] is the buying probability of the i-th friend, and
  q(i, j) is the probability that j of the first i friends (1, 2, ...i) 
  buy something, then:
    q(i, j) = p[i] * q(i - 1, j - 1) + (1 - p[i]) * q(i - 1, j).
*/

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

const int n_max = 20;
double p[n_max + 1];
  // p[i] is the buying probability of the i-th friend 
double q[n_max + 1][n_max + 1];
  // q[i][j] is the probability that j of the first i friends (1, 2, ...i)
  // buy something

int main()
{
  for (int c = 1; ; c++) {
    int n, r;
    cin >> n >> r;
    if (!n && !r)
      break;
    for (int i = 1; i <= n; i++)
      cin >> p[i];
    cout << "Case " << c << ":\n";
    memset(q, 0, sizeof(q));
    q[0][0] = 1.0;
    for (int i = 1; i <= n; i++) {
      q[i][0] = (1.0 - p[i]) * q[i - 1][0];
      for (int j = 1; j <= min(i, r); j++)
        q[i][j] = p[i] * q[i - 1][j - 1] + (1.0 - p[i]) * q[i - 1][j];
    }
    double t = q[n][r];
    for (int k = 1; k <= n; k++) {
      memset(q, 0, sizeof(q));
      q[0][0] = 1.0;
      for (int i = 1; i <= n; i++) {
        if (i == k) { // k-th friend buys something
          q[i][0] = 0.0;
          for (int j = 1; j <= min(i, r); j++)
            q[i][j] = p[i] * q[i - 1][j - 1];
        }
        else {
          q[i][0] = (1.0 - p[i]) * q[i - 1][0];
          for (int j = 1; j <= min(i, r); j++)
            q[i][j] = p[i] * q[i - 1][j - 1] + (1.0 - p[i]) * q[i - 1][j];
        }
      }
      printf("%.6lf\n", q[n][r] / t);
    }
  }
  return 0;
}

UVa 557 - Burger

Accepted date: 2012-01-19
Ranking (as of 2013-06-15): 236 out of 469
Language: C++

/*
  UVa 557 - Burger

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

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

/*
  Let p(n) be the probability that Ben and Bill get the same type of burger 
  for n guests, then:
    p(n) = 1.0 - C(n - 2, (n - 2) / 2) / 2^(n - 2).
  Here, C(n, k) is the number of k-combinations from a given set S of n elements.
  Let pf(n) =  C(n - 2, (n - 2) / 2) / 2^(n - 2).
  Then, using pf(n - 2), pf(n), pfn(n) can be calculated recursively as below:
    pf(n) = {(n - 3) / (n - 2)} * pf(n - 2).
    pf(2) = 1.0;
*/

const int n_max = 100000; // max. number of guests
double pf[1 + n_max / 2];

int main()
{
  pf[1] = 1.0;
  for (int i = 2; i <= n_max / 2; i++)
    pf[i] = pf[i - 1] *
      static_cast<double>(2 * i - 3) / static_cast<double>(2 * i - 2);
  int nr_problems;
  cin >> nr_problems;
  while (nr_problems--) {
    int n;
    cin >> n;
    printf("%.4lf\n", 1.0 - pf[n / 2]);
  }
  return 0;
}

UVa 10397 - Connect the Campus

Accepted date: 2012-01-23
Ranking (as of 2013-06-15): 289 out of 1935
Language: C++

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


Accepted date: 2012-01-23<br/>
Ranking (as of 2013-06-15): 289 out of 1935<br/>
Language: C++<br/>

<pre class="prettyprint">

/*
  UVa 10397 - Connect the Campus

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

/*
  Generate an undirected graph where vertices are buildings and each edge is 
  assigned a weight that is the Euclidean distance of the two vertices 
  adjacent to it.

  Calculate the minimum spanning tree of the graph applying Prim's algorithm, 
  and along the way, total the weight of all selected edges.

  This source code uses a priority queue implementation, pqueue, whose license 
  is described in the below comment.
*/

#include <iostream>
#include <utility>
#include <limits>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;

#ifdef  __cplusplus
extern "C" {
#endif

/** priority data type */
typedef double 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

struct vertex_distance
{
  int vertex; // vertex
  double distance; // distance
  size_t pqueue_pos; // used internally by libpqueue

  vertex_distance() : vertex(0), distance(0.0), pqueue_pos(-1) {}
  vertex_distance(int v, double d) : vertex(v), distance(d), pqueue_pos(-1) {}

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

double vertex_distance::get_distance(void* vd)
{
  return reinterpret_cast<vertex_distance*>(vd)->distance;
}

void vertex_distance::set_distance(void* vd, double d)
{
  reinterpret_cast<vertex_distance*>(vd)->distance = d;
}

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

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

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

const int nr_buildings_max = 750;
pair<int, int> buildings[nr_buildings_max];
bool cables[nr_buildings_max][nr_buildings_max];
  // cables[i][j] isi true if building i and j are connected by the cable
double matrix[nr_buildings_max][nr_buildings_max];
vertex_distance distances[nr_buildings_max];


double euclidean_distance(const pair<int, int>& p, const pair<int, int>& q)
{
  double dx = static_cast<double>(p.first - q.first),
    dy = static_cast<double>(p.second - q.second);
  return sqrt(dx * dx + dy * dy);
}

double mst_prim(int n)
{
  // queue items (vertex_distance instances) are arranged 
  // in ascending order of their distances from the first vertex
  pqueue_t* queue = pqueue_init(n,
    vertex_distance::compare_distance,
    vertex_distance::get_distance, vertex_distance::set_distance,
    vertex_distance::get_position, vertex_distance::set_position);
  for (int i = 0; i < n; i++)
    pqueue_insert(queue, &distances[i]);
  double mst_distance = 0.0;
  while (pqueue_size(queue)) {
    vertex_distance* vd = reinterpret_cast<vertex_distance*>(pqueue_pop(queue));
    vd->pqueue_pos = -1;
    int u = vd->vertex;
    mst_distance += distances[u].distance;
    for (int v = 0; v < n; v++)
      if (v != u && distances[v].pqueue_pos != -1
        // a vertex_distance instance for v is still in queue
        && matrix[u][v] < distances[v].distance) {
        pqueue_change_priority(queue, matrix[u][v], &distances[v]);
      }
  }
  pqueue_free(queue);
  return mst_distance;
}

int main()
{
  int n;
  while (cin >> n) {
    for (int i = 0; i < n; i++)
      cin >> buildings[i].first >> buildings[i].second;
    for (int i = 0; i < n; i++)
      for (int j = i + 1; j < n; j++)
        cables[i][j] = cables[j][i] = false;
    int m;
    cin >> m;
    for (int i = 0; i < m; i++) {
      int j, k;
      cin >> j >> k;
      j--; k--;
      cables[j][k] = cables[k][j] = true;
    }
    for (int i = 0; i < n; i++)
      for (int j = i + 1; j < n; j++)
        matrix[i][j] = matrix[j][i] =
          (cables[i][j]) ? 0.0 : euclidean_distance(buildings[i], buildings[j]);
    for (int i = 0; i < n; i++)
      distances[i] =
        vertex_distance(i, ((i) ? numeric_limits<double>::max() : 0.0));
    printf("%.2f\n", mst_prim(n));
  }
  return 0;
}

</pre>

UVa 10369 - Arctic Network

Accepted date: 2012-01-26
Ranking (as of 2013-06-15): 227 out of 1619
Language: C++

/*
  UVa 10369 - Arctic Network

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

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

class union_find {
public:
  union_find(int _n);
  ~union_find() {}
  int find(int i) const;
  int do_union(int i, int j);
    // generate the union of the two sets to which i and j belong and 
    // return the representative of the result set
  int nr_sets() const {return s_;}

private:
  int n_; // number of elements
  int s_; // number of sets
  vector<int> representatives_;
    // representatives[i] is the representative of a set to which i belongs
  vector<int> ranks_;
    // ranks_[i] is the number of elements in the set to which i belongs
};

union_find::union_find(int n)
  : n_(n), s_(n), representatives_(n), ranks_(n, 1)
{
  for (int i = 0; i < n_; i++)
    representatives_[i] = i;
}

int union_find::find(int i) const
// return the representative of a set to which i belongs
{
  return (representatives_[i] == i) ? i : find(representatives_[i]);
}

int union_find::do_union(int i, int j)
// generate the union of the two sets to which i and j belong and 
// return the representative of the result set
{
  int ri = find(i), rj = find(j);
  if (ri == rj) // already in the same set
    return -1;
  s_--;
  if (ranks_[ri] >= ranks_[rj]) {
    ranks_[ri] += ranks_[rj];
    representatives_[rj] = ri;
    return ri;
  }
  else {
    ranks_[rj] += ranks_[ri];
    representatives_[ri] = rj;
    return rj;
  }
}

struct edge {
  int u_, v_;
  double weight_;
  bool operator<(const edge& e) const {return weight_ < e.weight_;}
};

double euclidean_distance(const pair<int, int>& p, const pair<int,
  int>& q)
{
  double dx = static_cast<double>(p.first - q.first),
    dy = static_cast<double>(p.second - q.second);
  return sqrt(dx * dx + dy * dy);
}

int main()
{
  int n;
  cin >> n;
  while (n--) {
    int s, p;
    cin >> s >> p;
    vector< pair<int, int> > vertices(p);
    for (int i = 0; i < p; i++)
      cin >> vertices[i].first >> vertices[i].second;
    int nr_edges = p * (p - 1) / 2; // C(p, 2)
    vector<edge> edges(nr_edges);
    for (int i = 0, j = 0; j < p - 1; j++)
      for (int k = j + 1; k < p; k++) {
        edge& e = edges[i++];
        e.u_ = j; e.v_ = k;
        e.weight_ = euclidean_distance(vertices[j], vertices[k]);
      }
    sort(edges.begin(), edges.end());
    union_find forests(p);
    double min_d = 0.0;
    // using Kruskal algorithm, find "Minimum Spanning Forest" 
    // in the graph that has S components left
    for (int i = 0; i < nr_edges; i++)
      if (forests.do_union(edges[i].u_, edges[i].v_) != -1) {
        min_d = max(min_d, edges[i].weight_);
        if (forests.nr_sets() == s)
          break;
      }
    printf("%.2f\n", min_d);
  }
  return 0;
}

Thursday, June 13, 2013

UVa 658 - It's not a Bug, it's a Feature!

Accepted date: 2012-01-28
Ranking (as of 2013-06-13): 61 out of 396
Language: C++

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


/*
  UVa 658 - It's not a Bug, it's a Feature!

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

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#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

struct sequence
{
  int time_; // time that has been taken so far in seconds
  int bug_; // bit sets describing the bus
  size_t pqueue_pos_; // used internally by libpqueue

  sequence() : time_(-1), bug_(0), pqueue_pos_(-1) {}
  sequence(int time, int bug) : time_(time), bug_(bug), pqueue_pos_(-1) {}

  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 sequence::get_distance(void* vd)
{
  return reinterpret_cast<sequence*>(vd)->time_;
}

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

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

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

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

/*
  Starting with the state of "+++...+", apply Dijkstra's shortest path algorithm.
  For each state from the queue, see if any available patchs can be applied:
    For a bug of state '+', a patch of '0' or '+'
    For a bug of state '-', a patch of '0' or '-'
*/

struct patch {
  static int n_, mask_;
  int time_; // time in seconds it takes to apply the patch
  int before_present_;
    // bugs that have to be present before the patch can be applied
  int before_absent_;
    // bugs that have to be present before the patch can be applied
  int before_unaffected_;
    // bugs that doesn't matter whether it is present or not
  int after_present_; // bugs that are fixed by the patch
  int after_unaffected_;// bugs that are not affected by the patch

  static void set_mask(int n);
  patch() {}
  patch(int time, const string& before, const string& after);
  int apply(int bug) const;
};

int patch::n_ = 0, patch::mask_ = 0;

void patch::set_mask(int n)
{
  n_ = n; mask_ = (1 << n) - 1;
}

patch::patch(int time, const string& before, const string& after)
  : time_(time), before_present_(0), before_absent_(0), before_unaffected_(0),
  after_present_(0), after_unaffected_(0)
{
  for (int i = 0; i < n_; i++) {
    if (i) {
      before_present_ <<= 1; before_absent_ <<= 1;
      before_unaffected_ <<= 1;
      after_present_ <<= 1; after_unaffected_ <<= 1;
    }
    if (before[i] == '+')
      before_present_ |= 1;
    else if (before[i] == '-')
      before_absent_ |= 1;
    else
      before_unaffected_ |= 1;
    if (after[i] == '+')
      after_present_ |= 1;
    else if (after[i] == '0')
      after_unaffected_ |= 1;
  }
}

int patch::apply(int bug) const
{
  // see if the patch can be applied to bug, and if so, return the applied result
  int b = (bug & before_present_) | (~bug & before_absent_) | before_unaffected_;
  if (b != mask_)
    return -1;
  return after_present_ | (bug & after_unaffected_);
}

int shortest_path(int n, int m, const vector<patch>& patches)
{
  int nr_sequences = 1 << n;
  vector<sequence> sequences(nr_sequences);
    // sequences[i] is the sequence for the bug of i
  vector<bool> queued(nr_sequences, false);
    // queued[i] is true if bug of i has already been queued
  pqueue_t* queue = pqueue_init(nr_sequences,
    sequence::compare_distance, sequence::get_distance,
    sequence::set_distance, sequence::get_position, sequence::set_position);
  int start = patch::mask_;
  for (int i = 0; i < m; i++) {
    int bug = patches[i].apply(start);
    if (bug != -1) {
      sequences[bug] = sequence(patches[i].time_, bug);
      queued[bug] = true;
      pqueue_insert(queue, &sequences[bug]);
    }
  }
  int fixed_time = -1;
  while (pqueue_size(queue)) {
    sequence* s = reinterpret_cast<sequence*>(pqueue_pop(queue));
    s->pqueue_pos_ = -1;
    if (!s->bug_) {
      fixed_time = s->time_; break;
    }
    for (int i = 0; i < m; i++) {
      int bug = patches[i].apply(s->bug_);
      if (bug != -1) {
        int time = s->time_ + patches[i].time_;
        if (queued[bug]) {
          if (sequences[bug].pqueue_pos_ != -1 && sequences[bug].time_ > time)
            pqueue_change_priority(queue, time, &sequences[bug]);
        }
        else {
          sequences[bug] = sequence(time, bug);
          queued[bug] = true;
          pqueue_insert(queue, &sequences[bug]);
        }
      }
    }
  }
  pqueue_free(queue);
  return fixed_time;
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start;
#endif
  for (int pn = 1; ; pn++) {
    int n, m;
    cin >> n >> m;
#ifdef __ELAPSED_TIME__
    if (pn == 1)
      start = clock();
#endif
    if (!n && !m)
      break;
    patch::set_mask(n);
    vector<patch> patches(m);
    for (int i = 0; i < m; i++) {
      int time;
      string before, after;
      cin >> time >> before >> after;
      patches[i] = patch(time, before, after);
    }
    // apply Dijkstra's shortest path algorithm
    int fixed_time = shortest_path(n, m, patches);
    cout << "Product " << pn << endl;
    if (fixed_time != -1)
      cout << "Fastest sequence takes " << fixed_time << " seconds.\n";
    else
      cout << "Bugs cannot be fixed.\n";
    cout << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10801 - Lift Hopping

Accepted date: 2012-01-29
Ranking (as of 2013-06-13): 239 out of 1168
Language: C++

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


/*
  UVa 10801 - Lift Hopping

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

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <limits>
#include <cstdlib>
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

struct edge {
  int v; // destination vertex
  int weight; // waiting time or travelling time

  edge() : v(-1), weight(-1) {}
  edge(int _v, int _weight) : v(_v), weight(_weight) {}
};

struct vertex_distance
{
  int v; // vertex
  int distance; // distance
  size_t pqueue_pos; // used internally by libpqueue

  vertex_distance() : v(-1), distance(-1), pqueue_pos(-1) {}
  vertex_distance(int _v, int _distance)
    : v(_v), distance(_distance), pqueue_pos(-1) {}

  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 vertex_distance::get_distance(void* vd)
{
  return reinterpret_cast<vertex_distance*>(vd)->distance;
}

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

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

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

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

bool shortest_path(int nr_vertices, int start, int end,
  const vector< vector<edge> >& edges,
  vector<vertex_distance>& distances, vector<int>& parent_vertices)
{
  for (int i = 0; i < nr_vertices; i++)
    distances[i] = vertex_distance(i, ((i != start) ?
      numeric_limits<int>::max() : 0));
  // queue items (vertex_distance instances) are arranged in ascending order of 
  // their distances from the start vertex
  pqueue_t* queue = pqueue_init(distances.size(),
    vertex_distance::compare_distance,
    vertex_distance::get_distance, vertex_distance::set_distance,
    vertex_distance::get_position, vertex_distance::set_position);
  for (int i = 0; i < nr_vertices; i++)
    pqueue_insert(queue, &distances[i]);
  bool successful = false;
  while (pqueue_size(queue)) {
    vertex_distance* vd = reinterpret_cast<vertex_distance*>(pqueue_pop(queue));
    vd->pqueue_pos = -1;
    int u = vd->v;
    if (u == end) {
      successful = true; break;
    }
    int d = distances[u].distance;
    if (d == numeric_limits<int>::max())
      break;
    for (size_t i = 0; i < edges[u].size(); i++) {
      const edge& e = edges[u][i];
      if (distances[e.v].pqueue_pos != -1
        // an vertex_distance instance for t.route is still in queue
        && d + e.weight < distances[e.v].distance) {
        parent_vertices[e.v] = u;
        pqueue_change_priority(queue, d + e.weight, &distances[e.v]);
      }
    }
  }
  return successful;
}

int main()
{
  const int nr_floors = 100, s_wait = 60;
  string line;
  istringstream iss;
  while (getline(cin, line)) {
    iss.str(line);
    int n, k;
    iss >> n >> k;
    iss.clear();
    getline(cin, line);
    iss.str(line);
    vector<int> speeds(n);
    for (int i = 0; i < n; i++)
      iss >> speeds[i];
    iss.clear();
    vector< vector<edge> > edges(nr_floors);
      // edges[i] is the vector of edges from the i-th vertex
    for (int i = 0; i < n; i++) {
      getline(cin, line);
      iss.str(line);
      vector<int> floors(nr_floors);
      int j = 0;
      while (iss >> floors[j])
        j++;
      for (int fi = 0; fi < j - 1; fi++) {
        int fli = floors[fi];
        for (int fj = fi + 1; fj < j; fj++) {
          int flj = floors[fj];
          int s = speeds[i] * abs(flj - fli) + s_wait;
          edges[fli].push_back(edge(flj, s));
          edges[flj].push_back(edge(fli, s));
        }
      }
      iss.clear();
    }
    vector<vertex_distance> distances(nr_floors);
    vector<int> parent_vertices(nr_floors);
    // apply Dijkstra's shortest path algorithm
    bool successful =
      shortest_path(nr_floors, 0, k, edges, distances, parent_vertices);
    if (successful)
      cout << ((k) ? distances[k].distance - s_wait : 0) << endl;
    else
      cout << "IMPOSSIBLE\n";
  }
  return 0;
}

UVa 558 - Wormholes

Accepted date: 2012-02-01
Ranking (as of 2013-06-13): 639 out of 2762
Language: C++

/*
  558 - Wormholes

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

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

struct edge {
  int u_; // source vertex
  int v_; // destination vertex
  int weight_;

  edge() : u_(-1), v_(-1), weight_(-1) {}
  edge(int u, int v, int weight) : u_(u), v_(v), weight_(weight) {}
};

bool bellman_ford(int n, int source, const vector<edge>& edges)
{
  // initialize the graph
  vector<int> distances(n, numeric_limits<int>::max());
  distances[source] = 0;
  // relax the edges repeatedly
  for (int i = 0; i < n - 1; i++)
    for (size_t j = 0, je = edges.size(); j < je; j++) {
      const edge& e = edges[j];
      if (distances[e.u_] + e.weight_ < distances[e.v_])
        distances[e.v_] = distances[e.u_] + e.weight_;
    }
  // check for negative-weight cycles
  for (size_t i = 0, ie = edges.size(); i < ie; i++) {
    const edge& e = edges[i];
    if (distances[e.u_] + e.weight_ < distances[e.v_])
      return true; // the graph contains a negative-weight cycle
  }
  return false;
}

int main()
{
  int c;
  cin >> c;
  while (c--) {
    int n, m;
    cin >> n >> m;
    vector<edge> edges(m);
    for (int i = 0; i < m; i++)
      cin >> edges[i].u_ >> edges[i].v_ >> edges[i].weight_;
    cout << ((bellman_ford(n, 0, edges)) ? "possible\n" : "not possible\n");
  }
  return 0;
}

UVa 515 - King

Accepted date: 2012-02-04
Ranking (as of 2013-06-13): 172 out of 348
Language: C++

/*
  UVa 515 - King

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

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

struct edge {
  int u_; // source vertex
  int v_; // destination vertex
  int weight_;

  edge() : u_(-1), v_(-1), weight_(-1) {}
  edge(int u, int v, int weight) : u_(u), v_(v), weight_(weight) {}
};

bool bellman_ford(int n, int source, const vector<edge>& edges)
{
  // initialize the graph
  vector<int> distances(n, numeric_limits<int>::max());
  distances[source] = 0;
  // relax the edges repeatedly
  for (int i = 0; i < n - 1; i++)
    for (size_t j = 0, je = edges.size(); j < je; j++) {
      const edge& e = edges[j];
      if (distances[e.u_] + e.weight_ < distances[e.v_])
        distances[e.v_] = distances[e.u_] + e.weight_;
    }
  // check for negative-weight cycles
  for (size_t i = 0, ie = edges.size(); i < ie; i++) {
    const edge& e = edges[i];
    if (distances[e.u_] + e.weight_ < distances[e.v_])
      return true; // the graph contains a negative-weight cycle
  }
  return false;
}

int main()
{
  while (true) {
    int n;
    cin >> n;
    if (!n)
      break;
    int m;
    cin >> m;
    vector<edge> edges(n + m + 1);
    int i;
    for (i = 0; i < n + 1; i++)
      edges[i] = edge(n + 1, i, 0);
        // edges from specical vertex (n + 1) to any other vertex
    for ( ; i < n + m + 1; i++) {
      int j, k, c;
      string op;
      cin >> j >> k >> op >> c;
      k += j; j--;
      if (op == "gt") {
        swap(j, k);
        c++; c = -c;
      }
      else
        c--;
      edges[i] = edge(j, k, c);
    }
    // Bellman-Ford's shortest path algorithm should start 
    // from the special vertex (n + 1)
    cout << ((bellman_ford(n + 2, n + 1, edges)) ?
      "successful conspiracy\n" : "lamentable kingdom\n");
  }
  return 0;
}

Sunday, June 9, 2013

UVa 104 - Arbitrage

Accepted date: 2012-02-09
Ranking (as of 2013-06-09): 1087 out of 3240
Language: C++

/*
  UVa 104 - Arbitrage

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

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

void all_pairs_shortest_path(int n, const vector< vector<double> >& weights,
  vector< vector< vector<double> > >& distances,
  vector <vector< vector<int> > >& nexts)
{
  for (int u = 0; u < n; u++)
    for (int v = 0; v < n; v++)
      distances[u][v][0] = weights[u][v];
  for (int k = 1; k < n; k++)
    for (int u = 0; u < n; u++)
      for (int v = 0; v < n; v++) {
        distances[u][v][k] = numeric_limits<float>::max();
        for (int x = 0; x < n; x++) {
          double through_x = distances[u][x][k - 1] + weights[x][v];
          if (through_x < distances[u][v][k]) {
            distances[u][v][k] = through_x; nexts[u][v][k] = x;
          }
        }
      }
}

void print_path(int u, int v, int k,
  const vector <vector< vector<int> > >& nexts)
{
  int x = nexts[u][v][k];
  if (k) {
    print_path(u, x, k - 1, nexts);
    cout << ' ' << v + 1;
  }
  else
    cout << u + 1 << ' ' << v + 1;
}

bool print_arbitrage(int n, const vector< vector< vector<double> > >& distances,
  const vector <vector< vector<int> > >& nexts)
{
  for (int k = 0; k < n; k++)
    for (int u = 0; u < n; u++) {
      double profit = 1.0 / exp(distances[u][u][k]);
      if (profit > 1.01) {
        print_path(u, u, k, nexts);
        cout << endl;
        return true;
      }
    }
  return false;
}

int main()
{
  int n;
  while (cin >> n) {
    vector< vector<double> > weights(n, vector<double>(n));
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (i == j)
          weights[i][j] = 0.0; // log(1.0)
        else {
          double r;
          cin >> r;
          weights[i][j] = -log(r);
        }
    vector< vector< vector<double> > >
      distances(n, vector< vector<double> >(n, vector<double>(n)));
      // distance[u][v][k] is the shortest path from u to v that passes 
      // at most (k + 1) edges
    vector <vector< vector<int> > >
      nexts(n, vector< vector<int> >(n, vector<int>(n, -1)));
    all_pairs_shortest_path(n, weights, distances, nexts);
    if (!print_arbitrage(n, distances, nexts))
      cout << "no arbitrage sequence exists\n";
  }
  return 0;
}

UVa 488 - Triangle Wave

Accepted date: 2012-02-11
Ranking (as of 2013-06-09): 460 out of 8889
Language: C++

/*
  UVa 488 - Triangle Wave

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

#include <iostream>
using namespace std;

const char* waves[] = {
  "",
  "1\n",
  "1\n22\n1\n",
  "1\n22\n333\n22\n1\n",
  "1\n22\n333\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n88888888\n7777777\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n88888888\n999999999\n88888888\n7777777\n666666\n55555\n4444\n333\n22\n1\n"
};

int main()
{
  int nr_cases;
  cin >> nr_cases;
  while (nr_cases--) {
    int amplitude, frequency;
    cin >> amplitude >> frequency;
    if (amplitude < 0)
      amplitude = 0;
    const char* w = waves[amplitude];
    for (int f = 0; f < frequency; f++) {
      if (f)
        cout << endl;
      cout << w;
    }
    if (nr_cases)
      cout << endl;
        // outputs of two consecutive cases will be separated by a blank line
  }
  return 0;
}

UVa 10878 - Decode the tape

Accepted date: 2012-02-13
Ranking (as of 2013-06-09): 655 out of 3135
Language: C++

/*
  UVa 10878 - Decode the tape

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

#include <cstdio>

int main()
{
  const int nr_chrs = 16;
  char line[nr_chrs];
  while (gets(line)) {
    if (line[0] != '|') {
      continue;
    }
    char c = 0;
    for (int i = 1; i < 10; i++) {
      if (i > 1 && line[i] != '.')
        c <<= 1;
      if (line[i] == 'o')
        c |= 1;
    }
    putchar(c);
  }
  return 0;
}

UVa 10815 - Andy's First Dictionary

Accepted date: 2012-02-14
Ranking (as of 2013-06-09): 237 out of 3312
Language: C++

/*
  UVa 10815 - Andy's First Dictionary

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

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

int main()
{
  const int nr_chr_max = 256;
  char word[nr_chr_max + 1];
  set<string> words;
  while (scanf("%s", word) != EOF)
    for (int i = 0, length = strlen(word); i < length; /* i++ */) {
      while (i < length && !isalpha(word[i]))
        i++;
      if (i == length)
        break;
      int j = 0;
      char w[nr_chr_max + 1];
      for ( ; i < length && isalpha(word[i]); i++, j++)
        w[j] = static_cast<char>(tolower(word[i]));
      w[j] = '\0';
      words.insert(string(w));
    }
  for (set<string>::const_iterator i = words.begin(), e = words.end();
    i != e; ++i)
    printf("%s\n", (*i).c_str());
  return 0;
}

UVa 644 - Immediate Decodability

Accepted date: 2012-02-15
Ranking (as of 2013-06-09): 874 out of 2256
Language: C++

/*
  UVa 644 - Immediate Decodability

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

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

struct symbol
{
  int length_;
  int code_;
  symbol() : length_(-1), code_(0) {}
  symbol(int length, int code) : length_(length), code_(code) {}
  bool operator<(const symbol& s) const {return length_ < s.length_;}
};

bool is_immediate_decodable(int n, const symbol symbols[])
{
  int masks[] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
    0x00ff, 0x01ff, 0x03ff};
  for (int i = 0; i < n - 1; i++)
    for (int j = i + 1; j < n; j++) {
      int diff = symbols[i].code_ ^ symbols[j].code_;
      if (!(diff & masks[symbols[i].length_]))
        return false;
    }
  return true;
}

int main()
{
  const int nr_symbols_max = 8;
  string bc;
  for (int g = 1; cin >> bc; g++) {
    int nr_symbols = 0;
    symbol symbols[nr_symbols_max];
    do {
      int length = bc.length(), code = 0;
      for (int i = 0, b = 1; i < length; i++, b <<= 1)
        if (bc[i] == '1')
          code |= b;
      symbols[nr_symbols++] = symbol(length, code);
      cin >> bc;
    } while (bc != "9");
    sort(symbols, symbols + nr_symbols);
    cout << "Set " << g <<
      ((is_immediate_decodable(nr_symbols, symbols)) ?
      " is immediately decodable\n" : " is not immediately decodable\n");
  }
  return 0;
}

UVa 10115 - Automatic Editing

Accepted date: 2012-02-15
Ranking (as of 2013-06-09): 1037 out of 1867
Language: C++

/*
  UVa 10115 - Automatic Editing

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

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

const int nr_rules_max = 10;
const int nr_rule_chrs_max = 80, nr_text_chrs_max = 255;

struct find_replace_rule {
  char find_[nr_rule_chrs_max + 1];
  char replace_[nr_rule_chrs_max + 1];
} rules[nr_rules_max];

void apply_rule(const find_replace_rule* rule, char* text)
{
  const char *f = rule->find_, *r = rule->replace_;
  int fl = strlen(rule->find_), rl = strlen(rule->replace_);
  for ( ; *text; )
    if (!strncmp(text, f, fl)) {
      memmove(text + rl, text + fl, strlen(text + fl) + 1);
      memcpy(text, r, rl);
    }
    else
      text++;
}

int main()
{
  while (true) {
    char text[nr_text_chrs_max + 1];
    gets(text);
    int nr_rules;
    sscanf(text, "%d", &nr_rules);
    if (!nr_rules)
      break;
    for (int i = 0; i < nr_rules; i++) {
      gets(rules[i].find_);
      gets(rules[i].replace_);
    }
    gets(text);
    for (int i = 0; i < nr_rules; i++)
      apply_rule(rules + i, text);
    printf("%s\n", text);
  }
  return 0;
}

UVa 400 - Unix ls

Accepted date: 2012-02-19
Ranking (as of 2013-06-09): 794 out of 3046
Language: C++

/*
  UVa 400 - Unix ls

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

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

int main()
{
  const int max_length = 60;
  int nr_names;
  while (cin >> nr_names) {
    vector<string> names(nr_names);
    int max_name_length = 0;
    for (int i = 0; i < nr_names; i++) {
      cin >> names[i];
      max_name_length =
        max(max_name_length, static_cast<int>(names[i].length()));
    }
    sort(names.begin(), names.end());
    int nr_columns = 1;
    for (int l = max_name_length * 2 + 2;
      l <= max_length; l += max_name_length + 2)
      nr_columns++;
    int nr_rows = (nr_names + nr_columns - 1) / nr_columns;
    cout << "------------------------------------------------------------\n";
    for (int i = 0; i < nr_rows; i++) {
      for (int j = 0; j < nr_columns; j++) {
        int ni = i + nr_rows * j;
        if (ni < nr_names) {
          cout << names[ni];
          int l = max_name_length - names[ni].length();
          if (j < nr_columns - 1)
            l += 2;
          for (int k = 0; k < l; k++)
            cout << ' ';
        }
        else
          break;
      }
      cout << endl;
    }
  }
  return 0;
}

UVa 123 - Searching Quickly

Accepted date: 2012-02-19
Ranking (as of 2013-06-09): 619 out of 2304
Language: C++

/*
  UVa 123 - Searching Quickly

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

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <iterator>
#include <cctype>
using namespace std;

int main()
{
  set<string> words_to_ignore;
  while (true) {
    string s;
    cin >> s;
    if (s == "::")
      break;
    words_to_ignore.insert(s);
  }
  int nr_titles = 0;
  vector<string> titles;
  multimap< string, pair<int, int> > words;
    // key is a word in a titile, 
    // and its values are pair of an index to the vector of titles and 
    // its position in a title
  string t;
  while (getline(cin, t)) {
    transform(t.begin(), t.end(), t.begin(), (int(*)(int))tolower);
    const char* p = t.c_str();
    for (const char* q = p; *q; ) {
      while (*q == ' ')
        q++;
      const char* r = q;
      while (*r && *r != ' ')
        r++;
      string w(q, r - q);
      set<string>::iterator i = words_to_ignore.find(w);
      if (i == words_to_ignore.end())
        words.insert(make_pair(w, make_pair(nr_titles, q - p)));
      q = r;
    }
    titles.push_back(t);
    nr_titles++;
  }
  for (multimap< string, pair<int, int> >::const_iterator i = words.begin(),
    e = words.end(); i != e; ++i) {
    int length = i->first.length();
    pair<int, int> p = i->second;
    string t(titles[p.first]);
    // convert the keyword to upper-case letters
    string::iterator j = t.begin(), k = t.begin();
    advance(j, p.second);
    advance(k, p.second + length);
    transform(j, k, j, (int(*)(int))toupper);
    cout << t << endl;
  }
  return 0;
}

UVa 755 - 487-3279

Accepted date: 2012-02-20
Ranking (as of 2013-06-09): 461 out of 1887
Language: C++

/*
  UVa 755 - 487-3279

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

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <map>
#include <cctype>
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  const int letters[] = {2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 0, 7, 7,
    8, 8, 8, 9, 9, 9, 0};
  string line;
  istringstream iss(line);
  getline(cin, line);
  iss.str(line);
  int s;
  iss >> s;
  iss.clear();
  while (s--) {
    getline(cin, line); // skip a blank line
    getline(cin, line);
    iss.str(line);
    int n;
    iss >> n;
    iss.clear();
    map<int, int> tns;
      // key is a telephone number, value is its number of occurrences
    for (int i = 0; i < n; i++) {
      getline(cin, line);
      int tn = 0, j = 0;
      for (const char* p = line.c_str(); *p && j < 7; p++)
        if (isalnum(*p)) {
          if (j++)
            tn *= 10;
          if (isdigit(*p))
            tn += *p - '0';
          else
            tn += letters[*p - 'A'];
        }
      map<int, int>::iterator k = tns.find(tn);
      if (k == tns.end())
        tns.insert(make_pair(tn, 1));
      else
        k->second++;
    }
    bool duplicates = false;
    for (map<int, int>::const_iterator i = tns.begin(), e = tns.end();
      i != e; ++i)
      if (i->second > 1) {
        duplicates = true;
        cout << setfill('0') << setw(3) << i->first / 10000 <<
          '-' << setw(4) << i->first % 10000 <<
          ' ' << i->second << endl;
      }
    if (!duplicates)
      cout << "No duplicates.\n";
    if (s)
      cout << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

Saturday, June 8, 2013

UVa 10785 - The Mad Numerologist

Accepted date: 2012-02-21
Ranking (as of 2013-06-08): 165 out of 848
Language: C++

/*
  UVa 10785 - The Mad Numerologist

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

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

int main()
{
  const int n_max = 210, vowels_usage_max = 21, consonants_usage_max = 5;
  const char vowel_letters[] = {'A', 'U', 'E', 'O', 'I'};
  const char consonant_letters[] = {'J', 'S', 'B', 'K', 'T', 'C', 'L', 'D',
    'M', 'V', 'N', 'W', 'F', 'X', 'G', 'P', 'Y', 'H', 'Q', 'Z', 'R'};
  int nr_cases;
  cin >> nr_cases;
  for (int c = 1; c <= nr_cases; c++) {
    int n;
    cin >> n;
    int nr_vowels = (n + 1) / 2, nr_consonants = n / 2;
    char vowels[n_max + 1], consonants[n_max + 1];

    for (int i = 0, j = 0; i < nr_vowels; j++) {
      int k = min(nr_vowels - i, vowels_usage_max);
      memset(vowels + i, vowel_letters[j], k);
      i += k;
    }
    for (int i = 0, j = 0; i < nr_consonants; j++) {
      int k = min(nr_consonants - i, consonants_usage_max);
      memset(consonants + i, consonant_letters[j], k);
      i += k;
    }
    sort(vowels, vowels + nr_vowels);
    sort(consonants, consonants + nr_consonants);
    char name[n_max + 1];
    for (int i = 0; i < nr_vowels; i++)
      name[2 * i] = vowels[i];
    for (int i = 0; i < nr_consonants; i++)
      name[2 * i + 1] = consonants[i];
    name[nr_vowels + nr_consonants] = '\0';
    cout << "Case " << c << ": " << name << endl;
  }
  return 0;
}

UVa 10719 - Quotient Polynomial

Accepted date: 2012-02-25
Ranking (as of 2013-06-08): 366 out of 1072
Language: C++

/*
  UVa 10719 - Quotient Polynomial

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

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

const int n_max = 10000;
int a[n_max + 1];

int main()
{
  string line;
  istringstream iss;
  while (getline(cin, line)) {
    iss.str(line);
    int k;
    iss >> k;
    iss.clear();
    getline(cin, line);
    iss.str(line);
    int n = 0;
    while (iss >> a[n])
      n++;
    iss.clear();
    if (n == 1) {
      cout << "q(x):\nr = " << a[0] << endl << endl;
    }
    else {
      int b = a[0];
      cout << "q(x): " << b;
      for (int i = 1; i < n - 1; i++) {
        b = a[i] + k * b;
        cout << ' ' << b;
      }
      cout << endl;
      cout << "r = " << a[n - 1] + k * b << endl << endl;
    }
  }
  return 0;
}

UVa 11111 - Generalized Matrioshkas

Accepted date: 2012-03-10
Ranking (as of 2013-06-08): 518 out of 920
Language: C++

/*
  UVa 11111 - Generalized Matrioshkas

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

#include <iostream>
#include <string>
#include <sstream>
#include <stack>
#include <utility>
#include <cstdlib>
using namespace std;

int main(int /* argc */, char** /* argv */)
{
  string line;
  while (getline(cin, line)) {
    istringstream iss(line);
    stack< pair<int, int> > st;
      // first is the original capacity, second is the remaining capacity
    bool toys = false, valid = true;
    int n;
    while (iss >> n && valid) {
      toys = true;
      if (n < 0) { // start of a new toy
        n = labs(n);
        if (!st.empty()) {
          if (st.top().second <= n)
            valid = false;
          else
            st.top().second -= n;
        }
        st.push(make_pair(n, n));
      }
      else { // end of the toy
        if (st.empty() || st.top().first != n)
          valid = false;
        else
          st.pop();
      }
    }
    if (!toys || !st.empty())
      valid = false;
    cout << ((valid) ? ":-) Matrioshka!\n" : ":-( Try again.\n");
  }
  return 0;
}

UVa 699 - The Falling Leaves

Accepted date: 2012-03-13
Ranking (as of 2013-06-08): 444 out of 1351
Language: C++

/*
  UVa 699 - The Falling Leaves

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

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

struct Tree
{
  int nr_leaves_;
  int pos_;
  Tree* left_;
  Tree* right_;
  Tree(int nr_leaves, int pos) :
    nr_leaves_(nr_leaves), pos_(pos), left_(NULL), right_(NULL) {}
  ~Tree() {delete left_; delete right_;}
};

void build_tree(Tree* t, int& min_pos, int& max_pos)
{
  min_pos = min(min_pos, t->pos_);
  max_pos = max(max_pos, t->pos_);
  int nr_leaves;
  cin >> nr_leaves;
  if (nr_leaves != -1) {
    t->left_ = new Tree(nr_leaves, t->pos_ - 1);
    build_tree(t->left_, min_pos, max_pos);
  }
  cin >> nr_leaves;
  if (nr_leaves != -1) {
    t->right_ = new Tree(nr_leaves, t->pos_ + 1);
    build_tree(t->right_, min_pos, max_pos);
  }
}

void collect_leaves(Tree* t, int pos, vector<int>& piles)
{
  piles[pos + t->pos_] += t->nr_leaves_;
  if (t->left_)
    collect_leaves(t->left_, pos, piles);
  if (t->right_)
    collect_leaves(t->right_, pos, piles);
}

int main()
{
  for (int c = 1; ; c++) {
    int min_pos = 0, max_pos = 0;
    int nr_leaves;
    cin >> nr_leaves;
    if (nr_leaves == -1)
      break;
    Tree* root = new Tree(nr_leaves, 0);
    build_tree(root, min_pos, max_pos);
    vector<int> piles(max_pos - min_pos + 1, 0);
    collect_leaves(root, -min_pos, piles);
    delete root;
    cout << "Case " << c << ":\n";
    for (size_t i = 0, e = piles.size(); i < e; i++)
      cout << piles[i] << ((i == e - 1) ? '\n' : ' ');
    cout << endl;
  }
  return 0;
}

UVa 839 - Not so Mobile

Accepted date: 2012-03-15
Ranking (as of 2013-06-08): 384 out of 1166
Language: C++

/*
  UVa 839 - Not so Mobile

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

#include <iostream>
using namespace std;

struct Tree
{
  int left_distance_, right_distance_;
  int left_weight_, right_weight_;
  Tree* left_;
  Tree* right_;
  Tree(int left_distance, int right_distance, int left_weight, int right_weight)
    : left_distance_(left_distance), right_distance_(right_distance),
    left_weight_(left_weight), right_weight_(right_weight), left_(NULL),
    right_(NULL) {}
  ~Tree() {delete left_; delete right_;}
};

Tree* build_tree()
{
  int left_distance, right_distance, left_weight, right_weight;
  cin >> left_weight >> left_distance >> right_weight >>
    right_distance;
  Tree* t = new Tree(left_distance, right_distance, left_weight, right_weight);
  if (!left_weight)
    t->left_ = build_tree();
  if (!right_weight)
    t->right_ = build_tree();
  return t;
}

int calculate_tree_weight(Tree* t)
{
  if (t->left_ && (t->left_weight_ = calculate_tree_weight(t->left_)) == -1)
    return -1;
  if (t->right_ && (t->right_weight_ = calculate_tree_weight(t->right_)) == -1)
    return -1;
  return (t->left_weight_ * t->left_distance_ ==
    t->right_weight_ * t->right_distance_) ?
    t->left_weight_ + t->right_weight_ : -1;
}

int main()
{
  int nr_cases;
  cin >> nr_cases;
  while (nr_cases--) {
    Tree* root = build_tree();
    cout << ((calculate_tree_weight(root) == -1) ? "NO\n" : "YES\n");
    delete root;
    if (nr_cases)
      cout << endl;
  }
  return 0;
}

UVa 10562 - Undraw the Trees

Accepted date: 2012-03-17
Ranking (as of 2013-06-08): 319 out of 551
Language: C++

/*
  UVa 10562 - Undraw the Trees

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

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

const int nr_lines_max = 200, nr_chrs_max = 200;
string prof_tree[nr_lines_max + 1];

void print_tree(int nr_lines, int i, int j)
{
  if (i == nr_lines)
    cout << "()";
  else {
    const string& pt = prof_tree[i];
    if (j >= pt.length())
      cout << "()";
    else if (pt[j] == ' ')
      cout << "()";
    else if (pt[j] == '|')
      print_tree(nr_lines, i + 1, j);
    else if (pt[j] == '-') {
      while (j && pt[j - 1] == '-')
        j--;
      cout << '(';
      for ( ; pt[j] == '-'; j++) {
        if (j < prof_tree[i + 1].length() && prof_tree[i + 1][j] != ' ')
          print_tree(nr_lines, i + 1, j);
      }
      cout << ')';
    }
    else {
      cout << pt[j];
      print_tree(nr_lines, i + 1, j);
    }
  }
}

int main()
{
  string s;
  getline(cin, s);
  istringstream iss(s);
  int t;
  iss >> t;
  while (t--) {
    int nr_lines = 0;
    while (true) {
      getline(cin, prof_tree[nr_lines]);
      if (prof_tree[nr_lines][0] == '#')
        break;
      nr_lines++;
    }
    cout << '(';
    if (nr_lines) {
      const string& pt = prof_tree[0];
      for (int j = 0, e = pt.length(); j < e; j++)
        if (pt[j] != ' ') {
          cout << pt[j];
          print_tree(nr_lines, 1, j);
        }
    }
    cout << ")\n";
  }
  return 0;
}

UVa 10557 - XYZZY

Accepted date: 2012-03-21
Ranking (as of 2013-06-08): 287 out of 802
Language: C++

/*
  UVa 10557 - XYZZY

  To build using Visual Studio 20&08:
    cl -EHsc -O2 xyzzy.cpp
*/

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

bool bfs(int n, int s, int e, const vector< vector<int> >& rooms)
{
  vector<bool> visited(n, false);
  queue<int> q;
  visited[s] = true;
  q.push(s);
  while (!q.empty()) {
    int i = q.front(); q.pop();
    if (i == e)
      return true;
    for (vector<int>::const_iterator j = rooms[i].begin(), k = rooms[i].end();
      j != k; ++j)
      if (!visited[*j]) {
        visited[*j] = true;
        q.push(*j);
      }
  }
  return false;
}

bool bellman_ford(int n,
  const vector<int>& energies, const vector< pair<int, int> >& doors,
  const vector< vector<int> >& rooms)
{
  if (n == 1)
    return true;
  // initialize the graph
  vector<long long> distances(n, numeric_limits<int>::max());
  distances[0] = -100;
  // relax the edges repeatedly
  for (int i = 0; i < n - 1; i++) {
    for (size_t j = 0, e = doors.size(); j < e; j++) {
      const pair<int, int>& d = doors[j];
      if (distances[d.first] + energies[d.first] < min(0LL, distances[d.second]))
        distances[d.second] = distances[d.first] + energies[d.first];
    }
    if (distances[n - 1] < 0)
      return true;
  }
  // check for negative-weight cycles
  for (size_t i = 0, e = doors.size(); i < e; i++) {
    const pair<int, int>& d = doors[i];
    if (distances[d.first] + energies[d.first] < min(0LL, distances[d.second]) &&
      bfs(n, 0, d.first, rooms) && bfs(n, d.second, n - 1, rooms))
        // cycle is reachable both from start and to finish
      return true;
  }
  return false;
}

int main()
{
  while (true) {
    int n;
    cin >> n;
    if (n == -1)
      break;
    vector<int> energies(n); // energies[i] is the energy of i-th room
    vector< pair<int, int> > doors(n);
      // there is a one-way door form doors[].first to doors[].second
    vector< vector<int> > rooms(n);
    for (int i = 0; i < n; i++) {
      int e;
      cin >> e;
      energies[i] = -e;
      int j;
      cin >> j;
      for (int k = 0; k < j; k++) {
        int l;
        cin >> l;
        doors.push_back(make_pair(i, l - 1));
        rooms[i].push_back(l - 1);
      }
    }
    cout << (bellman_ford(n, energies, doors, rooms) ?
      "winnable\n" : "hopeless\n");
  }
  return 0;
}

UVa 10047 - The Monocycle

Accepted date: 2012-03-24
Ranking (as of 2013-06-08): 707 out of 1044
Language: C++

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


/*
  UVa 10047 - The Monocycle

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

#include <iostream>
#include <vector>
#include <limits>
#include <cstdlib>
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

enum {dir_unknown = -1, dir_north, dir_south, dir_west, dir_east};
enum {clr_red, clr_black, clr_green, clr_white, clr_blue};
const int nr_dirs = dir_east - dir_north + 1, nr_colors = clr_blue - clr_red + 1;

struct vertex_distance
{
  int v_; // vertex
  int distance_; // distance
  int direction_, color_;
  size_t pqueue_pos_; // used internally by libpqueue

  vertex_distance() : v_(-1), distance_(-1), pqueue_pos_(-1) {}
  vertex_distance(int v, int distance, int direction, int color)
    : v_(v), distance_(distance), direction_(direction), color_(color),
    pqueue_pos_(-1) {}

  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 vertex_distance::get_distance(void* vd)
{
  return reinterpret_cast<vertex_distance*>(vd)->distance_;
}

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

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

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

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

bool relax_distance(int m, int n, const vector< vector<char> >& squares,
  int next_dir, int di, vector<vertex_distance>& distances, pqueue_t* queue)
{
  int i = di / (n * nr_dirs * nr_colors);
  int j = (di - i * (n * nr_dirs * nr_colors)) / (nr_dirs * nr_colors);
  switch (next_dir) {
  case dir_north:
    i--; break;
  case dir_south:
    i++; break;
  case dir_west:
    j--; break;
  case dir_east:
    j++; break;
  }
  if (i < 0 || i >= m || j < 0 || j >= n || squares[i][j] == '#')
    return false;
  int next_color = (distances[di].color_ + 1) % nr_colors;
  int k = i * (n * nr_dirs * nr_colors) + j * nr_dirs * nr_colors +
    next_dir * nr_colors + next_color;
  if (distances[k].pqueue_pos_ == -1) 
    // an vertex_distance instance is not in the queue
    return false;
  const int ds[nr_dirs][nr_dirs] = {
    {1, 3, 2, 2}, // from north
    {3, 1, 2, 2}, // from south
    {2, 2, 1, 3}, // from east
    {2, 2, 3, 1} // from west
  };
  int d = distances[di].distance_ + ds[distances[di].direction_][next_dir];
  if (d < distances[k].distance_) {
    pqueue_change_priority(queue, d, &distances[k]);
    return true;
  }
  else
    return false;
}

int shortest_path(int m, int n, int start, int end,
  const vector< vector<char> >& squares)
{
  int nr_vertices = m * n * nr_dirs * nr_colors;
  vector<vertex_distance> distances(nr_vertices);
  for (int i = 0; i < m; i++)
    for (int j = 0; j < n; j++)
      for (int d = 0; d < nr_dirs; d++)
        for (int c = 0; c < nr_colors; c++) {
          int l = i * (n * nr_dirs * nr_colors) + j * nr_dirs * nr_colors +
            d * nr_colors + c;
          if (i * n + j == start && d == dir_north && c == clr_green)
            distances[l] = vertex_distance(l, 0, d, c);
          else
            distances[l] = vertex_distance(l, numeric_limits<int>::max(), d, c);
        }
  // queue items (vertex_distance instances) are arranged in ascending order of 
  // their distances from the start vertex
  pqueue_t* queue = pqueue_init(distances.size(),
    vertex_distance::compare_distance, vertex_distance::get_distance,
    vertex_distance::set_distance, vertex_distance::get_position,
    vertex_distance::set_position);
  for (int i = 0; i < nr_vertices; i++)
    pqueue_insert(queue, &distances[i]);
  while (pqueue_size(queue)) {
    vertex_distance* vd = reinterpret_cast<vertex_distance*>(pqueue_pop(queue));
    vd->pqueue_pos_ = -1;
    int i = vd->v_ / (n * nr_dirs * nr_colors);
    int j = (vd->v_ - i * (n * nr_dirs * nr_colors)) / (nr_dirs * nr_colors);
    int d = vd->distance_;
    if (d == numeric_limits<int>::max())
      break;
#ifdef DEBUG
    cout << i << ' ' << j << ' ' << d << endl;
#endif
    if (i * n + j == end && vd->color_ == clr_green)
      return vd->distance_;
    relax_distance(m, n, squares, dir_north, vd->v_, distances, queue);
    relax_distance(m, n, squares, dir_south, vd->v_, distances, queue);
    relax_distance(m, n, squares, dir_west, vd->v_, distances, queue);
    relax_distance(m, n, squares, dir_east, vd->v_, distances, queue);
  }
  return -1;
}

int main()
{
  for (int c = 1; ; c++) {
    int m, n;
    cin >> m >> n;
    if (!m && !n)
      break;
    if (c > 1)
      cout << endl; // print a blank line between two successive test cases
    vector< vector<char> > squares(m, vector<char>(n));
    int s, t;
    for (int i = 0; i < m; i++)
      for (int j = 0; j < n; j++) {
        cin >> squares[i][j];
        if (squares[i][j] == 'S')
          s = i * n + j;
        else if (squares[i][j] == 'T')
          t = i * n + j;
      }
    int min_path = shortest_path(m, n, s, t, squares);
    cout << "Case #" << c << endl;
    if (min_path == -1)
      cout << "destination not reachable\n";
    else
      cout << "minimum time = " << min_path << " sec\n";
  }
  return 0;
}