Saturday, December 28, 2013

UVa 11105 - Semi-prime H-numbers

Accepted date: 2013-12-28
Ranking (as of 2013-12-28): 121 out of 608
Language: C++

/*
  UVa 11105 - Semi-prime H-numbers

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11105_Semi_prime_H_numbers.cpp
*/

#include <iostream>
using namespace std;

const int h_nr_max = 1000001;

int h_numbers[h_nr_max + 1];
  // h_numbers[i] is the number of product of H-numbers
int semi_prime_h_numbers[h_nr_max + 1];
  // semi_prime_h_numbers[i] is the number of semi-prime H-numbers up to i

int main()
{
  for (int i = 5; i <= h_nr_max; i += 4) {
    if (!h_numbers[i])
      h_numbers[i] = 1;
    for (int j = 5; j <= i && i * j <= h_nr_max; j += 4)
      h_numbers[i * j] = h_numbers[i] + h_numbers[j];
  }
#ifdef DEBUG
  int prime_h_numbers = 0;
#endif
  for (int i = 5; i <= h_nr_max; i += 4) {
    semi_prime_h_numbers[i] = semi_prime_h_numbers[i - 4];
    if (h_numbers[i] == 2)
      semi_prime_h_numbers[i]++;
#ifdef DEBUG
    else if (h_numbers[i] == 1)
      prime_h_numbers++;
#endif
  }
#ifdef DEBUG
  cout << prime_h_numbers << ' ' << semi_prime_h_numbers[h_nr_max] << endl;
#endif
  while (true) {
    int h;
    cin >> h;
    if (!h)
      break;
    cout << h << ' ' << semi_prime_h_numbers[h] << endl;
  }
  return 0;
}

Friday, December 27, 2013

UVa 12478 - Hardest Problem Ever (Easy)

Accepted date: 2013-12-27
Language: C++

/*
  UVa 12478 - Hardest Problem Ever (Easy)

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_12478_Hardest_Problem_Ever.cpp
*/

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

const char* names[] = {
  "RAKIBUL", "ANINDYA", "MOSHIUR", "SHIPLU", "KABIR", "SUNNY", "OBAIDA", "WASI"
};

const int nr_rows = 9, nr_columns = 9;

const char grid[nr_rows][nr_columns] = {
  {'O', 'B', 'I', 'D', 'A', 'I', 'B', 'K', 'R'},
  {'R', 'K', 'A', 'U', 'L', 'H', 'I', 'S', 'P'},
  {'S', 'A', 'D', 'I', 'Y', 'A', 'N', 'N', 'O'},
  {'H', 'E', 'I', 'S', 'A', 'W', 'H', 'I', 'A'},
  {'I', 'R', 'A', 'K', 'I', 'B', 'U', 'L', 'S'},
  {'M', 'F', 'B', 'I', 'N', 'T', 'R', 'N', 'O'},
  {'U', 'T', 'O', 'Y', 'Z', 'I', 'F', 'A', 'H'},
  {'L', 'E', 'B', 'S', 'Y', 'N', 'U', 'N', 'E'},
  {'E', 'M', 'O', 'T', 'I', 'O', 'N', 'A', 'L'}
};

#ifdef DEBUG
bool search_name(const char* name, int length)
{
  for (int r = 0; r < nr_rows; r++)
    for (int c = 0; c <= nr_columns - length; c++) {
      int ci;
      for (ci = 0; ci < length; ci++)
        if (name[ci] != grid[r][c + ci])
          break;
      if (ci == length) {
        printf("  horozontal %d %d: %s\n", r, c, name);
        return true;
      }
    }
  for (int r = 0; r <= nr_rows - length; r++)
    for (int c = 0; c < nr_columns; c++) {
      int ri;
      for (ri = 0; ri < length; ri++)
        if (name[ri] != grid[r + ri][c])
          break;
      if (ri == length) {
        printf(" vertical    %d %d: %s\n", r, c, name);
        return true;
      }
    }
  return false;
}
#endif

int main()
{
#ifdef DEBUG
  for (size_t i = 0; i < sizeof(names) / sizeof(const char*); i++) {
    char name[8];
    strcpy(name, names[i]);
    puts(name);
    int length = strlen(name);
    sort(name, name + length);
    int nr_found = 0;
    do {
      if (search_name(name, length)) {
        if (++nr_found == 2)
          break;
      }
    } while (next_permutation(name, name + length));
/*
    if (nr_found == 2) {
      puts(names[i]);
      break;
    }
*/
  }
#else
  puts(names[4]);
#endif
  return 0;
}

Monday, December 23, 2013

UVa 10482 - The Candyman Can

Accepted date: 2013-12-23
Ranking (as of 2013-12-23): 91 out of 648
Language: C++

/*
  UVa 10482 - The Candyman Can

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10482_The_Candyman_Can.cpp
*/

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

const int n_max = 32, weight_max = 20;
const int sum_of_weights_max = n_max * weight_max;

int weights[n_max + 1];
int sum_of_weights[n_max + 1]; // sum of weghts up to i
bool subset_sums[sum_of_weights_max + 1][sum_of_weights_max + 1];
  // subset_sums[a][b] is true if there is a subset of weights 
  // whose sums are a, b

int badness(int s, int a, int b)
{
  int c = s - (a + b);
  return max(max(a, b), c) - min(min(a, b), c);
}

int main()
{
  int t;
  cin >> t;
  for (int c = 1; c <= t; c++) {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
      cin >> weights[i];
      sum_of_weights[i] = sum_of_weights[i - 1] + weights[i];
    }
    int s = sum_of_weights[n];
    for (int a = 0; a <= s; a++)
      for (int b = 0; b <= s; b++)
          subset_sums[a][b] = false;
    subset_sums[0][0] = true;
    for (int i = 1; i <= n; i++) {
      int si = sum_of_weights[i], wi = weights[i];
      for (int a = si; a >= 0; a--)
        for (int b = si; b >= 0; b--)
          if (a >= wi && subset_sums[a - wi][b] ||
            b >= wi && subset_sums[a][b - wi])
            subset_sums[a][b] = true;
#ifdef DEBUG
      cout << i << ':';
      for (int a = 0; a <= si; a++)
        for (int b = 0; b <= si; b++)
          if (subset_sums[a][b]) 
            cout << " [" << a << ", " << b << ']';
      cout << endl;
#endif
    }
    int min_badness = s;
    for (int a = 0; a <= s; a++)
      for (int b = 0; b <= s; b++)
        if (subset_sums[a][b])
          min_badness = min(min_badness, badness(s, a, b));
    cout << "Case " << c << ": " << min_badness << endl;
  }
  return 0;
}

Saturday, December 21, 2013

UVa 139 - Telephone Tangles

Accepted date: 2013-12-21
Ranking (as of 2013-12-21): 65 out of 592
Language: C++

/*
  UVa 139 - Telephone Tangles

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_139_Telephone_Tangles.cpp
*/

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

const int nr_chars_number = 15, nr_chars_locality = 25, nr_chars_max = 1023;

struct telephone_code {
  int code_length_;
  char code_[nr_chars_number + 1];
  char locality_[nr_chars_locality + 1];
  double cost_;
};

int main()
{
  vector<telephone_code> telephone_codes;
  while (true) {
    char s[nr_chars_max + 1];
    gets(s);
    if (!strcmp(s, "000000"))
      break;
    telephone_code tc;
    char* p = strchr(s, ' ');
    *p++ = '\0';
    strcpy(tc.code_, s);
    tc.code_length_ = strlen(tc.code_);
    char *q = strchr(p, '$');
    *q++ = '\0';
    strcpy(tc.locality_, p);
    sscanf(q, "%lf", &tc.cost_);
    tc.cost_ /= 100.0;
    telephone_codes.push_back(tc);
  }
  int nr_tc_codes = static_cast<int>(telephone_codes.size());
  while (true) {
    char number[nr_chars_number + 1];
    scanf("%s", number);
    if (number[0] == '#')
      break;
    int duration;
    scanf("%d", &duration);
    int tci = -1;
    if (number[0] == '0') {
      for (tci = 0; tci < nr_tc_codes; tci++)
        if (!strncmp(number, telephone_codes[tci].code_,
          telephone_codes[tci].code_length_)) {
          int length = strlen(&number[telephone_codes[tci].code_length_]);
          if (length < 4)
            continue;
          if (telephone_codes[tci].code_[1] == '0') { // IDD
            if (length <= 10)
              break;
          }
          else { // STD
            if (length <= 7)
              break;
          }
        }
    }
    if (tci == -1)
      printf("%-15s %-5s%30s%5d%6.2lf%7.2lf\n",
        number, "Local", number, duration, 0.0, 0.0);
    else if (tci < nr_tc_codes)
      printf("%-15s %-25s%10s%5d%6.2lf%7.2lf\n",
        number, telephone_codes[tci].locality_,
        &number[telephone_codes[tci].code_length_], duration,
        telephone_codes[tci].cost_, telephone_codes[tci].cost_ * duration);
    else
      printf("%-15s %-35s%5d%13.2lf\n", number, "Unknown", duration, -1.0);
  }
  return 0;
}

Friday, December 20, 2013

UVa 10819 - Trouble of 13-Dots

Accepted date: 2013-12-19
Ranking (as of 2013-12-19): 93 out of 805
Language: C++

/*
  UVa 10819 - Trouble of 13-Dots

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10819_Trouble_of_13_Dots.cpp
*/

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

const int m_max = 10000 + 200, n_max = 100;
int max_favours[m_max + 1];
  // max_favours[i] is the max. total favour valus for the expense of i

int main()
{
  int m, n;
  while (scanf("%d %d", &m, &n) != EOF) {
    int expense = m;
    if (m > 1800) // m + 200 > 2000
      expense += 200;
    memset(max_favours, 0, sizeof(max_favours));
    for (int i = 0; i < n; i++) {
      int p, f;
      scanf("%d %d", &p, &f);
      for (int j = expense; j > p; j--)
        if (max_favours[j - p])
          max_favours[j] = max(max_favours[j], max_favours[j - p] + f);
      max_favours[p] = max(max_favours[p], f);
#ifdef DEBUG
    for (int j = 0; j <= expense; j++)
      if (max_favours[j])
        printf("\t%d %d\n", j, max_favours[j]);
#endif
    }
    int max_f = 0;
    for (int i = 1; i <= expense; i++) {
      if (m <= 2000 && i > m && i <= 2000)
        continue;
      if (max_favours[i] > max_f)
        max_f = max_favours[i];
    }
    printf("%d\n", max_f);
  }
  return 0;
}

Monday, December 16, 2013

UVa 967 - Circular

Accepted date: 2013-12-16
Ranking (as of 2013-12-16): 180 out of 601
Language: C++

/*
  UVa 967 - Circular

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_967_Circular.cpp
*/

#include <cstdio>
#include <cmath>

const int n_max = 1000000;
bool not_primes[n_max + 1]; // not_primes[i] is true if i is not a prime
int nr_circular_primes[n_max + 1];
  // nr_circular_primes[i] is the number of circular primes up to i

void sieve_of_eratosthenes()
{
  for (int i = 2, e = static_cast<int>(sqrt(static_cast<double>(n_max)));
    i <= e; i++)
    if (!not_primes[i]) {
      for (int j = i * i; j <= n_max; j += i)
        not_primes[j] = true;
    }
}

int get_number(int length, int* digits)
{
  int n = 0;
  for (int i = 0; i < length; i++, digits++) {
    if (i)
      n *= 10;
    n += *digits;
  }
  return n;
}

bool is_circular_prime(int n)
{
  if (not_primes[n])
    return false;
  const int nr_digits_max = 8;
  int digits[nr_digits_max * 2];
  int length;
  for (length = 1; ; length++) {
    digits[nr_digits_max - length] = n % 10;
    n /= 10;
    if (!n)
      break;
  }
  for (int i = nr_digits_max - length, j = nr_digits_max, k = length - 1;
    k; k--) {
    digits[j++] = digits[i++];
    if (not_primes[get_number(length, &digits[i])])
      return false;
  }
  return true;
}

int main()
{
  sieve_of_eratosthenes();
  int nr = 0;
  for (int n = 100; n <= n_max; n++) {
    if (is_circular_prime(n))
      nr++;
    nr_circular_primes[n] = nr;
  }
  while (true) {
    int i, j;
    scanf("%d", &i);
    if (i == -1)
      break;
    scanf("%d", &j);
    nr = nr_circular_primes[j] - nr_circular_primes[i - 1];
    if (!nr)
      puts("No Circular Primes.");
    else if (nr == 1)
      puts("1 Circular Prime.");
    else
      printf("%d Circular Primes.\n", nr);
  }
  return 0;
}

Sunday, December 15, 2013

UVa 944 - Happy Numbers

Accepted date: 2013-12-15
Ranking (as of 2013-12-15): 62 out of 603
Language: C++

/*
  UVa 944 - Happy Numbers

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_944_Happy_Numbers.cpp
*/

#include <cstdio>
#include <cstring>

const int n_max = 99999, sum_of_squares_max = 405;

enum {unknown, happy, unhappy};

struct happy_number {
  int happy_; // 0 for unknown, 1 for happy, 2 for unhappy
  int nr_iterations_;
} happy_numbers[n_max + 1];

int sum_of_squares[sum_of_squares_max + 1];
  // sum_of_squares[i] is the number whose sum of squares is i

int calculate_sum_of_squares(int n)
{
  int d, s = 0;
  do {
    d = n % 10;
    s += d * d;
    n /= 10;
  } while (n);
  return s;
}

void set_happy_numbers(int number, int nr_iterations)
{
  do {
    happy_numbers[number].happy_ = happy;
    happy_numbers[number].nr_iterations_ = nr_iterations++;
    number = sum_of_squares[number];
  } while (number != -1);
}

void set_unhappy_numbers(int number)
{
  do {
    happy_numbers[number].happy_ = unhappy;
    number = sum_of_squares[number];
  } while (number != -1);
}

int main()
{
  int n;
  for (n = 1; n <= sum_of_squares_max; n++) {
    if (happy_numbers[n].happy_ == unknown) {
      int m = n;
      memset(sum_of_squares, 0, sizeof(sum_of_squares));
      sum_of_squares[m] = -1;
      while (true) {
        int s = calculate_sum_of_squares(m);
        if (s == 1 || happy_numbers[s].happy_ == happy) {
          set_happy_numbers(m, happy_numbers[s].nr_iterations_ + 1);
          break;
        }
        else if (sum_of_squares[s] || happy_numbers[s].happy_ == unhappy) {
          set_unhappy_numbers(m);
          break;
        }
        sum_of_squares[s] = m;
        m = s;
      }
    }
#ifdef DEBUG
    if (happy_numbers[n].happy_ == happy)
      printf("%d %d\n", n, happy_numbers[n].nr_iterations_);
#endif
  }
  for ( ; n <= n_max; n++) {
    int s = calculate_sum_of_squares(n);
    if (happy_numbers[s].happy_ == happy) {
      happy_numbers[n].happy_ = happy;
      happy_numbers[n].nr_iterations_ = happy_numbers[s].nr_iterations_ + 1;
#ifdef DEBUG
      printf("%d %d\n", n, happy_numbers[n].nr_iterations_);
#endif
    }
    else
      happy_numbers[n].happy_ = unhappy;
  }
  bool printed = false;
  int l, h;
  while (scanf("%d %d", &l, &h) != EOF) {
    if (printed)
      putchar('\n');
    else
      printed = true;
    for (n = l; n <= h; n++)
      if (happy_numbers[n].happy_ == happy)
        printf("%d %d\n", n, happy_numbers[n].nr_iterations_);
  }
  return 0;
}

Tuesday, December 3, 2013

UVa 11678 - Cards' Exchange

Accepted date: 2013-12-03
Ranking (as of 2013-12-03): 66 out of 606
Language: C++

/*
  UVa 11678 - Cards' Exchange

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11678_Cards_Exchange.cpp
*/

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

const int nr_cards_max = 10000;
int alice_cards[nr_cards_max], betty_cards[nr_cards_max];

int skip_cards(int nc, int ic, const int cards[])
{
  int c = cards[ic++];
  for ( ; ic < nc; ic++)
    if (cards[ic] != c)
        break;
  return ic;
}

int main()
{
  while (true) {
    int na, nb;
    scanf("%d %d", &na, &nb);
    if (!na & !nb)
      break;
    for (int i = 0; i < na; i++)
      scanf("%d", &alice_cards[i]);
    for (int i = 0; i < nb; i++)
      scanf("%d", &betty_cards[i]);
    int xa = 0, xb = 0;
    for (int ia = 0, ib = 0; ia < na || ib < nb; ) {
      if (ia < na && ib < nb) {
        if (alice_cards[ia] < betty_cards[ib]) {
          xa++;
          ia = skip_cards(na, ia, alice_cards);
        }
        else if (alice_cards[ia] > betty_cards[ib]) {
          xb++;
          ib = skip_cards(nb, ib, betty_cards);
        }
        else {
          ia = skip_cards(na, ia, alice_cards);
          ib = skip_cards(nb, ib, betty_cards);
        }
      }
      else if (ia < na) {
        xa++;
        ia = skip_cards(na, ia, alice_cards);
      }
      else {
        xb++;
        ib = skip_cards(nb, ib, betty_cards);
      }
    }
    printf("%d\n", min(xa, xb));
  }
  return 0;
}

UVa 11258 - String Partition

Accepted date: 2013-12-02
Ranking (as of 2013-12-03): 219 out of 630
Language: C++

/*
  UVa 11258 - String Partition

  To build using Visual Studio 2012:
    cl -EHsc -O2 -DONLINE_JUDGE UVa_11258_String_Partition.cpp
*/

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

const int nr_digits_max = 200;
#ifdef ONLINE_JUDGE
long long max_sum[nr_digits_max];
  // max_s[i] is the max. sum of digits up to i
#else
long long max_sum[nr_digits_max][nr_digits_max];
  // max_s[i][j] is the max. sum of digits bewteen i-th and j-th
#endif

int get_integer(const char s[], int si, int sj)
{
  long long i = s[si++] - '0';
  for ( ; si <= sj; si++) {
    i *= 10;
    i += s[si] - '0';
    if (i > INT_MAX)
      return -1;
  }
  return i;
}

int main()
{
  int n;
  scanf("%d", &n);
  while (n--) {
    char digits[nr_digits_max + 1];
    scanf("%s", digits);
    int n = strlen(digits);
#if ONLINE_JUDGE
    max_sum[0] = digits[0] - '0';
    for (int i = 1; i < n; i++) {
      long long max_s = get_integer(digits, 0, i);
      for (int j = 1; j <= 10 && j <= i; j++) {
        int k = get_integer(digits, i - j + 1, i);
        if (k != -1)
          max_s = max(max_s, max_sum[i - j] + k);
      }
      max_sum[i] = max_s;
    }
    printf("%lld\n", max_sum[n - 1]);
#else
    for (int i = 0; i < n; i++)
      max_sum[i][i] = digits[i] - '0';
    for (int k = 0; k < n; k++)
      for (int i = 0; i < n - k; i++) {
        long long max_s = get_integer(digits, i, i + k);
        for (int j = i; j < i + k; j++)
          max_s = max(max_s, max_sum[i][j] + max_sum[j + 1][i + k]);
        max_sum[i][i + k] = max_s;
      }
#ifdef DEBUG
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
      printf("%lld%c", max_sum[i][j], ((j < n - 1) ? ' ' : '\n'));
#endif
    printf("%lld\n", max_sum[0][n - 1]);
#endif
  }
  return 0;
}

Saturday, November 23, 2013

UVa 10610 - Gopher and Hawks

Accepted date: 2013-11-23
Ranking (as of 2013-11-23): 94 out of 637
Language: C++

/*
  UVa 10610 - Gopher and Hawks

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10610_Gopher_and_Hawks.cpp
*/

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

const int n_max = 1024;
  // when I defined n_max = 1000, I got a verdict of Runtime error.

pair<double, double> holes[n_max];
vector<int> edges[n_max];
bool visited[n_max];

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

int bfs(int n, int s, int t, const vector<int> edges[])
{
  queue< pair<int, int> > q;
  visited[s] = true;
  q.push(make_pair(s, 0));
  while (!q.empty()) {
    pair<int, int> u = q.front();
    q.pop();
    if (u.first == t)
      return u.second - 1;
    const vector<int>& e = edges[u.first];
    for (size_t i = 0, j = e.size(); i < j; i++) {
      int k = e[i];
      if (!visited[k]) {
        visited[k] = true;
        q.push(make_pair(k, u.second + 1));
      }
    }
  }
  return -1;
}

int main()
{
  string line;
  istringstream iss;
  while (true) {
    getline(cin, line);
    iss.str(line);
    int v, m;
    iss >> v >> m;
    iss.clear();
    if (!v && !m)
      break;
    double d = 60.0 * v * m;
    int n = 0;
    while (true) {
      getline(cin, line);
      if (line.empty())
        break;
      iss.str(line);
      iss >> holes[n].first >> holes[n].second;
      iss.clear();
      n++;
    }
    for (int i = 0; i < n; i++) {
      edges[i].clear();
      visited[i] = false;
    }
    for (int i = 0; i < n - 1; i++)
      for (int j = i + 1; j < n; j++)
        if (euclidean_distance(holes[i], holes[j]) <= d) {
          edges[i].push_back(j);
          edges[j].push_back(i);
        }
    int nr_holes = bfs(n, 0, 1, edges);
    if (nr_holes != -1)
      cout << "Yes, visiting " << nr_holes << " other holes.\n";
    else
      cout << "No.\n";
  }
  return 0;
}

UVa 837 - Light and Transparencies

Accepted date: 2013-11-23
Ranking (as of 2013-11-23): 528 out of 672
Language: C++

/*
  UVa 837 - Light and Transparencies

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_837_Light_and_Transparencies.cpp
*/

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

struct point {
  double x_;
  int tci_; // index to tcs[]
};

struct tc { // transparent coeficients
  bool effective_;
  double r_;
};

bool compare_point(const point& p, const point& q)
{
  return p.x_ < q.x_;
}

int main()
{
  int t;
  cin >> t;
  while (t--) {
    int nl;
    cin >> nl;
    int np = nl * 2;
    vector<point> points(np);
    vector<tc> tcs(nl);
    for (int i = 0; i < nl; i++) {
      double y1, y2;
      cin >> points[i * 2].x_ >> y1 >> points[i * 2 + 1].x_ >> y2 >> tcs[i].r_;
      points[i * 2].tci_ = points[i * 2 + 1].tci_ = i;
      tcs[i].effective_ = false;
    }
    sort(points.begin(), points.end(), compare_point);
    cout << np + 1 << endl;
    cout << fixed;
    for (int i = 0; i <= np; i++) {
      if (i)
        cout << setprecision(3) << points[i - 1].x_;
      else
          cout << "-inf";
      if (i < np)
          cout << ' ' << setprecision(3) << points[i].x_;
      else
        cout << " +inf";
      double pl = 1.0; // percentage of light
      if (i && i < np) {
        for (int j = 0; j < nl; j++)
          if (tcs[j].effective_)
            pl *= tcs[j].r_;
      }
      cout << ' ' << setprecision(3) << pl << endl;
      if (i < np)
        tcs[points[i].tci_].effective_ = !tcs[points[i].tci_].effective_;
    }
    if (t)
      cout << endl;
  }
  return 0;
}

Monday, November 18, 2013

UVa 776 - Monkeys in a Regular Forest

Accepted date: 2013-11-18
Ranking (as of 2013-11-18): 147 out of 641
Language: C++

/*
  UVa 776 - Monkeys in a Regular Forest

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_776_Monkeys_in_a_Regular_Forest.cpp
*/

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

void bfs(int nr_rows, int nr_columns, int r, int c, int fn,
  const vector< vector<char> >& forest, vector< vector<int> >& monkeys)
{
  const int nr_dirs = 8;
  const int dirs[nr_dirs][2] =
    {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};
  char fc = forest[r][c];
  queue<pair<int, int> > q;
  monkeys[r][c] = fn;
  q.push(make_pair(r, c));
  while (!q.empty()) {
    pair<int, int> rc = q.front();
    q.pop();
    for (int i = 0; i < nr_dirs; i++) {
      r = rc.first + dirs[i][0]; c = rc.second + dirs[i][1];
      if (r >= 0 && r < nr_rows && c >= 0 && c < nr_columns &&
        forest[r][c] == fc && !monkeys[r][c]) {
        monkeys[r][c] = fn;
        q.push(make_pair(r, c));
      }
    }
  }
}

int main()
{
  string line;
  while (getline(cin, line)) {
    vector< vector<char> > forest;
    do {
      if (line[0] == '%')
        break;
      forest.push_back(vector<char>());
      istringstream iss(line);
      char c;
      while (iss >> c)
        forest.back().push_back(c);
    } while (getline(cin, line));
    int nr_rows = static_cast<int>(forest.size()),
      nr_columns = static_cast<int>(forest[0].size());
    vector< vector<int> > monkeys(nr_rows, vector<int>(nr_columns, 0));
    for (int r = 0, fn = 0; r < nr_rows; r++)
      for (int c = 0; c < nr_columns; c++)
        if (!monkeys[r][c])
          bfs(nr_rows, nr_columns, r, c, ++fn, forest, monkeys);
    vector<int> widths(nr_columns, 0);
    for (int c = 0; c < nr_columns; c++) {
      for (int r = 0; r < nr_rows; r++) {
        int fn = monkeys[r][c], w = ((c) ? 1 : 0);
        do {
          fn /= 10;
          w++;
        } while (fn);
        widths[c] = max(widths[c], w);
      }
    }
    cout << setfill(' ');
    for (int r = 0;r < nr_rows; r++) {
      for (int c = 0; c < nr_columns; c++)
        cout << setw(widths[c]) << monkeys[r][c];
      cout << endl;
    }
    cout << "%\n";
  }
  return 0;
}

Friday, November 15, 2013

UVa 296 - Safebreaker

Accepted date: 2013-11-15
Ranking (as of 2013-11-15): 30 out of 639
Language: C++

/*
  UVa 296 - Safebreaker

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_296_Safebreaker.cpp
*/

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

const int nr_digits = 4, nr_guesses_max = 10, number_max = 10000;

struct guess {
  char code_[nr_digits + 1];
  int nr_correct_, nr_misplaced_;
};

void get_code(int n, char* code)
{
  for (int i = nr_digits - 1; i >= 0; i--) {
    code[i] = n % 10 + '0';
    n /= 10;
  }
}

bool is_consistent(const char* code, const guess* g)
{
  int nr_correct = 0;
  unsigned char correct = 0;
    // bit i (0 <= i <= 4) is 1 if i-th character is correct
  for (int i = 0, bi = 1; i < nr_digits; i++, bi <<= 1)
    if (code[i] == g->code_[i]) {
      correct |= bi;
      nr_correct++;
    }
  if (nr_correct != g->nr_correct_)
    return false;
  int nr_misplaced = 0;
  unsigned char misplaced = 0;
    // bit i (0 <= i <= 4) is 1 if i-th character is misplaced
  for (int i = 0, bi = 1; i < nr_digits; i++, bi <<= 1)
    if (!(correct & bi)) {
      int j = i + 1;
      if (j == nr_digits)
        j = 0;
      while (j != i) {
        int bj = 1 << j;
        if (!(correct & bj) && !(misplaced & bj) && code[i] == g->code_[j]) {
          misplaced |= bj;
          nr_misplaced++;
          break;
        }
        if (++j == nr_digits)
          j = 0;
      }
    }
  return nr_misplaced == g->nr_misplaced_;
}

int main()
{
  int n;
  cin >> n;
  while (n--) {
    int g;
    cin >> g;
    guess guesses[nr_guesses_max];
    for (int i = 0; i < g; i++) {
      char separator;
      cin >> guesses[i].code_ >> guesses[i].nr_correct_
        >> separator >> guesses[i].nr_misplaced_;
    }
    int nr_consistent = 0;
    char code[nr_digits + 1], secret_code[nr_digits + 1];
    code[nr_digits] = '\0';
    for (int i = 0; i < number_max; i++) {
      get_code(i, code);
      int j;
      for (j = 0; j < g; j++)
        if (!is_consistent(code, &guesses[j]))
          break;
      if (j == g) {
        if (!nr_consistent++)
          strcpy(secret_code, code);
      }
    }
    if (nr_consistent == 1)
      cout << secret_code << endl;
    else if (nr_consistent)
      cout << "indeterminate\n";
    else
      cout << "impossible\n";
  }
  return 0;
}

Thursday, November 14, 2013

UVa 10901 - Ferry Loading III

Accepted date: 2013-11-13
Ranking (as of 2013-11-14): 201 out of 669
Language: C++

/*
  UVa 10901 - Ferry Loading III

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10901_Ferry_Loading_III.cpp
*/

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

const int m_max = 10000;

struct car {
  int at_; // arrival time
  int ut_; // unloaded time
  int ab_; // arrival bank
} cars[m_max];

int cars_at_left_bank[m_max], cars_at_right_bank[m_max];
  // cars_at_left/right_bank[i] is the index to cars[] that arrives at 
  // left/right bank

enum {left, right};

int main()
{
  int c;
  scanf("%d", &c);
  while (c--) {
    int n, t, m;
    scanf("%d %d %d", &n, &t, &m);
    int mlb = 0, mrb = 0; // number of cars that arrives at left/right bank
    for (int i = 0; i < m; i++) {
      char s[8];
      scanf("%d %s", &cars[i].at_, s);
      if (s[0] == 'l') {
        cars[i].ab_ = left;
        cars_at_left_bank[mlb++] = i;
      }
      else {
        cars[i].ab_ = right;
        cars_at_right_bank[mrb++] = i;
      }
    }
    int ft = 0, fb = left;
    for (int ilb = 0, irb = 0; ilb < mlb || irb < mrb; ) {
      int i, b;
      if (ilb < mlb && irb < mrb) {
        int il = cars_at_left_bank[ilb], ir = cars_at_right_bank[irb];
        if (fb == left && cars[il].at_ <= ft)
          i = il;
        else if (fb == right && cars[ir].at_ <= ft)
          i = ir;
        else if (cars[il].at_ < cars[ir].at_)
          i = il;
        else if (cars[il].at_ > cars[ir].at_)
          i = ir;
        else
          i = (fb == left) ? il : ir;
      }
      else if (ilb < mlb)
        i = cars_at_left_bank[ilb];
      else
        i = cars_at_right_bank[irb];
      b = cars[i].ab_;
      if (cars[i].at_ > ft)
        ft += cars[i].at_ - ft;
      if (fb != cars[i].ab_) {
        ft += t;
        fb = cars[i].ab_;
      }
      if (b == left)
        for (int j = 0; ilb < mlb && cars[cars_at_left_bank[ilb]].at_ <= ft
          && j < n; ilb++, j++)
          cars[cars_at_left_bank[ilb]].ut_ = ft + t;
      else
        for (int j = 0; irb < mrb && cars[cars_at_right_bank[irb]].at_ <= ft
          && j < n; irb++, j++)
          cars[cars_at_right_bank[irb]].ut_ = ft + t;
      ft += t;
      fb = (fb == left) ? right : left;
    }
    for (int i = 0; i < m; i++)
      printf("%d\n", cars[i].ut_);
    if (c)
      putchar('\n');
  }
  return 0;
}

UVa 11344 - The Huge One

Accepted date: 2013-11-12
Ranking (as of 2013-11-14): 316 out of 678
Language: C++

/*
  UVa 11344 - The Huge One

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11344_The_Huge_One.cpp
*/

#include <cstdio>
#include <cstring>

bool is_multiple_of_1(const char* number, int length)
{
  return true;
}

bool is_multiple_of_2(const char* number, int length)
{
  return ((number[length - 1] - '0') % 2) ? false : true;
}

bool is_multiple_of_3(const char* number, int length)
{
  int s = 0;
  for (int i = 0; i < length; i++)
    s += number[i] - '0';
  return (s % 3) ? false : true;
}

bool is_multiple_of_4(const char* number, int length)
{
  int s = number[length - 1] - '0';
  if (length > 1)
    s += (number[length - 2] - '0') * 10;
  return (s % 4) ? false : true;
}

bool is_multiple_of_5(const char* number, int length)
{
  return ((number[length - 1] - '0') % 5) ? false : true;
}

bool is_multiple_of_6(const char* number, int length)
{
  return is_multiple_of_2(number, length) && is_multiple_of_3(number,length);
}

bool is_multiple_of_7(const char* number, int length)
{
  int s = 0;
  for (int i = 0, j = length - 1; j >= 0; i++) {
    int k = number[j--] - '0';
    if (j >= 0)
      k += (number[j--] - '0') * 10;
    if (j >= 0)
      k += (number[j--] - '0') * 100;
    if (i & 1)
      s -= k;
    else
      s += k;
  }
  return (s % 7) ? false : true;
}

bool is_multiple_of_8(const char* number, int length)
{
  int s = number[length - 1] - '0';
  if (length > 1) {
    s += (number[length - 2] - '0') * 10;
    if (length > 2)
      s += (number[length - 3] - '0') * 100;
  }
  return (s % 8) ? false : true;
}

bool is_multiple_of_9(const char* number, int length)
{
  int s = 0;
  for (int i = 0; i < length; i++)
    s += number[i] - '0';
  return (s % 9) ? false : true;
}

bool is_multiple_of_10(const char* number, int length)
{
  return number[length - 1] == '0';
}

bool is_multiple_of_11(const char* number, int length)
{
  int s = 0;
  for (int i = 0, j = length - 1; j >= 0; i++, j--) {
    int k = number[j] - '0';
    if (i & 1)
      s -= k;
    else
      s += k;
  }
  return (s % 11) ? false : true;
}

bool is_multiple_of_12(const char* number, int length)
{
  return is_multiple_of_3(number, length) && is_multiple_of_4(number, length);
}

int main()
{
  typedef bool (*IS_MULTIPLE_OF_N_FUNCTION)(const char* number, int length);
  const IS_MULTIPLE_OF_N_FUNCTION is_multiple_of_n_functions[] = {
    NULL,
    is_multiple_of_1, is_multiple_of_2, is_multiple_of_3,
    is_multiple_of_4, is_multiple_of_5, is_multiple_of_6,
    is_multiple_of_7, is_multiple_of_8, is_multiple_of_9,
    is_multiple_of_10, is_multiple_of_11, is_multiple_of_12
  };

  int N;
  scanf("%d", &N);
  while (N--) {
    const int M_digits_max = 1001;
    char M[M_digits_max + 1];
    scanf("%s", M);
    int length = strlen(M), S;
    scanf("%d", &S);
    bool wonderful = true;
    while (S--) {
      int number;
      scanf("%d", &number);
      if (wonderful && !is_multiple_of_n_functions[number](M, length))
        wonderful = false;
    }
    printf("%s - %s.\n", M, ((wonderful) ? "Wonderful" : "Simple"));
  }
  return 0;
}

Thursday, October 31, 2013

UVa 391 - Mark-up

Accepted date: 2013-10-31
Language: C++

/*
  UVa 391 - Mark-up

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_391_Mark_up.cpp
*/

#include <cstdio>
#include <cctype>

int main()
{
  bool mark_ups = true;
  int c;
  while ((c = getchar()) != EOF) {
    if (c == '\\') {
      if ((c = getchar()) == EOF) {
        putchar('\\');
        return 0;
      }
      else if (c == '*')
        mark_ups = !mark_ups;
      else if (mark_ups) {
        switch (c) {
        case 'b': case 'i':
          break;
        case 's':
          do
            c = getchar();
          while (isdigit(c) || c == '.');
          if (c == EOF)
            return 0;
          else
            ungetc(c, stdin);
          break;
        default:
          putchar(c);
          break;
        }
      }
      else {
        ungetc(c, stdin);
        putchar('\\');
      }
    }
    else
      putchar(c);
  }
  return 0;
}

Tuesday, October 29, 2013

UVa 10016 - Flip-Flop the Squarelotron

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

/*
  UVa 10016 - Flip-Flop the Squarelotron

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10016_Flip_Flop_the_Squarelotron.cpp
*/

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

const int n_max = 100;
int matrix[n_max][n_max];

/*
For the rgi-th ring (rgi >= 0), the corresponding elements of matrix are:
  matrix[rgi][rgi] - matrix[rgi][n - 1 - rgi] // top row
  matrix[n - 1 - rgi][rgi] - matrix[n - 1 - rgi][n - 1 - rgi] // bottom row

  matrix[rgi][rgi] - matrix[n - 1 - rgi][rgi] // left column
  matrix[rgi][n - 1 - rgi] - matrix[n - 1 - rgi][n - 1 - rgi] // right column
*/

enum {upside_down = 1, left_right, main_diagonal, main_inverse_diagonal};

void upside_down_flip(int n, int rgi)
{
  for (int c = rgi; c < n - rgi; c++)
    swap(matrix[rgi][c], matrix[n - 1 - rgi][c]);
  for (int r = rgi + 1; r < n / 2; r++) {
    swap(matrix[r][rgi], matrix[n - 1 - r][rgi]);
    swap(matrix[r][n - 1 - rgi], matrix[n - 1 - r][n - 1 - rgi]);
  }
}

void left_right_flip(int n, int rgi)
{
  for (int r = rgi; r < n - rgi; r++)
    swap(matrix[r][rgi], matrix[r][n - 1 - rgi]);
  for (int c = rgi + 1; c < n / 2; c++) {
    swap(matrix[rgi][c], matrix[rgi][n - 1 - c]);
    swap(matrix[n - 1 - rgi][c], matrix[n - 1 - rgi][n - 1 - c]);
  }
}

void main_diagonal_flip(int n, int rgi)
{
  for (int c = rgi + 1; c < n - rgi; c++)
    swap(matrix[rgi][c], matrix[c][rgi]);
  for (int c = rgi + 1; c < n - rgi - 1; c++)
    swap(matrix[n - 1 - rgi][c], matrix[c][n - 1 - rgi]);
}

void main_inverse_diagonal_flip(int n, int rgi)
{
  for (int c = rgi; c < n - rgi - 1; c++)
    swap(matrix[rgi][c], matrix[n - 1 - c][n - 1 - rgi]);
  for (int c = rgi + 1; c < n - rgi - 1; c++)
    swap(matrix[n - 1 - rgi][c], matrix[n - 1 - c][rgi]);
}

int main()
{
  int m;
  scanf("%d", &m);
  while (m--) {
    int n;
    scanf("%d", &n);
    for (int r = 0; r < n; r++)
      for (int c = 0; c < n; c++)
        scanf("%d", &matrix[r][c]);
    for (int rgi = 0, nr_rings = (n + 1) / 2; rgi < nr_rings; rgi++) {
      int t;
      scanf("%d", &t);
      while (t--) {
        int c;
        scanf("%d", &c);
        switch (c) {
        case upside_down:
          upside_down_flip(n, rgi);
          break;
        case left_right:
          left_right_flip(n, rgi);
          break;
        case main_diagonal:
          main_diagonal_flip(n, rgi);
          break;
        case main_inverse_diagonal:
          main_inverse_diagonal_flip(n, rgi);
          break;
        }
#ifdef DEBUG
        for (int r = 0; r < n; r++)
          for (int c = 0; c < n; c++)
            fprintf(stderr, "%d%c", matrix[r][c], ((c == n - 1) ? '\n' : ' '));
#endif
      }
    }
    for (int r = 0; r < n; r++)
      for (int c = 0; c < n; c++)
        printf("%d%c", matrix[r][c], ((c == n - 1) ? '\n' : ' '));
  }
  return 0;
}

Sunday, October 27, 2013

UVa 10247 - Complete Tree Labeling

Accepted date: 2011-02-15
Ranking (as of 2013-10-27): 164 out of 453
Language: JAVA

/*
  6.6.5 Complete Tree Labeling
  PC/UVa IDs: 110605/10247, Popularity: C, Success rate: average Level: 2
*/

/*
total number of nodes for a k-ary tree of depth d = Σ(i = 0 to d) pow(k, i) = 
  (pow(k, d + 1) - 1) / (k - 1).
number of nodes at the i-th level of depth = pow(k, i), 
  each of which has pow(k, i + 1) nodes.
*/

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

class Main {
  static int numberOfNodes(int k, int d) {
    // number of nodes for a k-ary tree of depth d
    return ((int)Math.pow((double)k, (double)d + 1.0) - 1) / (k - 1);
  }

  static BigInteger factorial(int n) {
    BigInteger f = BigInteger.ONE;
    for (int i = 1; i <= n; i++)
      f = f.multiply(BigInteger.valueOf(i));
    return f;
  }

  static HashMap<Long, BigInteger> combinationCache = 
    new HashMap<Long, BigInteger>();

  static BigInteger combination(int n, int k) {
    if (k == 0 || n == k)
      return BigInteger.ONE;
    else {
      long nk = (long)n << 32 | k;
      BigInteger c = combinationCache.get(nk);
      if (c != null)
        return c;
      c = factorial(n).divide(factorial(n - k).multiply(factorial(k)));
      combinationCache.put(nk, c);
      return c;
    }
  }

  static HashMap<Long, BigInteger> cache = new HashMap<Long, BigInteger>();

  static BigInteger completeTreeLabeling(
    int k /* branching factor */, int d /* depth */) {
    if (k == 1)
      return BigInteger.ONE;
    long kd = (long)k << 32 | d;
    BigInteger nrLabeling = cache.get(kd);
    if (nrLabeling != null)
      return nrLabeling;
    nrLabeling = factorial(k);
    if (d > 1) {
      // number of nodes for a k-ary tree of depth d
      int nrNodes = numberOfNodes(k, d);
      // number of descendants of the root node for a k-ary tree of depth (d - 1)
      int nrDescendants = numberOfNodes(k, d - 1) - 1;
      // number of labeling for a k-ary tree of depth (d - 1)
      BigInteger nrDescendantsLabeling = completeTreeLabeling(k, d - 1);
      for (int i = nrNodes - 2; i >= nrDescendants; i -= nrDescendants + 1) {
        BigInteger c = combination(i, nrDescendants);
        nrLabeling = nrLabeling.multiply(c).multiply(nrDescendantsLabeling);
      }
    }
    cache.put(kd, nrLabeling);
    return nrLabeling;
  }

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    while (sc.hasNextInt()) {
      int k = sc.nextInt();
      if (sc.hasNextInt()) {
        int d = sc.nextInt();
        System.out.println(completeTreeLabeling(k, d));
      }
    }
  }
}

UVa 183 - Bit Maps

Accepted date: 2013-10-27
Language: C++

/*
  UVa 183 - Bit Maps

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_183_Bit_Maps.cpp
*/

#include <cstdio>

const int rows_max = 200, columns_max = 200;
int bitmap[rows_max][columns_max];
int sums[rows_max][columns_max];
  // sum[i][j] is the sum of bitmap[bi][bj] (0 <= bi <= i, 0 <= bj <= j)
const int nr_chars_max = 50;
int nr_chars;

int zeros_ones(int top, int left, int bottom, int right)
{
  int s = sums[bottom][right];
  if (top && left)
    s += sums[top - 1][left - 1] - sums[top - 1][right] - sums[bottom][left - 1];
  else if (top)
    s -= sums[top - 1][right];
  else if (left)
    s -= sums[bottom][left - 1];
  if (!s)
    return 0; // all zeros
  else if (s == (bottom - top + 1) * (right - left + 1))
    return 1; // all ones
  else
    return -1;
}

void bitmap_putchar(char c)
{
  putchar(c);
  if (++nr_chars == nr_chars_max) {
    nr_chars = 0;
    putchar('\n');
  }
}

void quarters(int top, int left, int bottom, int right)
{
  int zo = zeros_ones(top, left, bottom, right);
  if (zo >= 0) // all zeros or ones
    bitmap_putchar(static_cast<char>(zo + '0'));
  else {
    bitmap_putchar('D');
    int rows = bottom - top + 1, columns = right - left + 1;
    if (rows > 1 && columns > 1) {
      quarters(top, left, top + (rows - 1) / 2, left + (columns - 1) / 2);
      quarters(top, left + (columns + 1) / 2, top + (rows - 1) / 2,  right);
      quarters(top + (rows + 1) / 2, left, bottom, left + (columns - 1) / 2);
      quarters(top + (rows + 1) / 2, left + (columns + 1) / 2, bottom, right);
    }
    else if (rows > 1) {
      quarters(top, left, top + (rows - 1) / 2, right);
      quarters(top + (rows + 1) / 2, left, bottom, right);
    }
    else {
      quarters(top, left, bottom, left + (columns - 1) / 2);
      quarters(top, left + (columns + 1) / 2, bottom,  right);
    }
  }
}

void decomposition(int rows, int columns)
{
  for (int r = 0; r < rows; r++) {
    int ones = 0;
    for (int c = 0; c < columns; c++) {
      char zero_or_one;
      do
        zero_or_one = getchar();
      while (zero_or_one == '\n');
      bitmap[r][c] = zero_or_one - '0';
      ones += bitmap[r][c];
      sums[r][c] = ones;
      if (r)
        sums[r][c] += sums[r - 1][c];
    }
  }
#ifdef DEBUG
  for (int r = 0; r < rows; r++)
    for (int c = 0; c < columns; c++)
      fprintf(stderr, "%4d%c", bitmap[r][c], ((c == columns - 1) ? '\n' : ' '));
  for (int r = 0; r < rows; r++)
    for (int c = 0; c < columns; c++)
      fprintf(stderr, "%4d%c", sums[r][c], ((c == columns - 1) ? '\n' : ' '));
#endif
  quarters(0, 0, rows - 1, columns - 1);
  if (nr_chars)
    putchar('\n');
}

void composition(int top, int left, int bottom, int right)
{
  char c;
  do
    c = getchar();
  while (c == '\n');
  if (c == '0' || c == '1') {
    c -= '0';
    for (int i = top; i <= bottom; i++)
      for (int j = left; j <= right; j++)
        bitmap[i][j] = c;
  }
  else { // 'D'
    int rows = bottom - top + 1, columns = right - left + 1;
    if (rows > 1 && columns > 1) {
      composition(top, left, top + (rows - 1) / 2, left + (columns - 1) / 2);
      composition(top, left + (columns + 1) / 2, top + (rows - 1) / 2,  right);
      composition(top + (rows + 1) / 2, left, bottom, left + (columns - 1) / 2);
      composition(top + (rows + 1) / 2, left + (columns + 1) / 2, bottom, right);
    }
    else if (rows > 1) {
      composition(top, left, top + (rows - 1) / 2, right);
      composition(top + (rows + 1) / 2, left, bottom, right);
    }
    else {
      composition(top, left, bottom, left + (columns - 1) / 2);
      composition(top, left + (columns + 1) / 2, bottom,  right);
    }
  }
}

int main()
{
  while (true) {
    char format[2];
    scanf("%s", format);
    if (format[0] == '#')
      break;
    int rows, columns;
    scanf("%d %d", &rows, &columns);
    nr_chars = 0;
    if (format[0] == 'B') {
      printf("%c%4d%4d\n", 'D', rows, columns);
      decomposition(rows, columns);
    }
    else {
      composition(0, 0, rows - 1, columns - 1);
      printf("%c%4d%4d\n", 'B', rows, columns);
      for (int r = 0; r < rows; r++)
        for (int c = 0; c < columns; c++)
          bitmap_putchar(static_cast<char>(bitmap[r][c] + '0'));
        if (nr_chars)
          putchar('\n');
    }
  }
  return 0;
}

Saturday, October 26, 2013

UVa 10043 - Chainsaw Massacre

Accepted date: 2011-05-23
Ranking (as of 2013-10-26): 80 out of 387
Language: C++

/*
  14.7.3 Chainsaw Massacre
  PC/UVa IDs: 111403/10043, Popularity: B, Success rate: low Level: 3

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

/*
  This is an application of maximum (or largest) empty rectangle problem.
*/

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

struct point {
  int x, y;

  point() : x(0), y(0) {}
  point(int _x, int _y) : x(_x), y(_y) {}
  point(const point &p) : x(p.x), y(p.y) {}
  bool operator==(const point& p) const {return x == p.x && y == p.y;}
};

bool left_lower_order(const point& p1, const point& p2)
{
  if (p1.x < p2.x)
    return true;
  else if (p1.x > p2.x)
    return false;
  else if (p1.y < p2.y)
    return true;
  else
    return false;
}

bool upper_order(const point& p1, const point& p2)
{
  return p1.y > p2.y;
}

int maximum_empty_rectangle(int l, int w, vector<point>& points)
{
  if (points.empty())
    return l * w;
  sort(points.begin(), points.end(), left_lower_order);
    // sort the points in leftmost-lowest order
  for (vector<point>::iterator i = points.begin();
    i != points.end(); ) { // remove the duplicate points
    vector<point>::iterator j = i;
    j++;
    if (j != points.end() && *i == *j)
      i = points.erase(i);
    else
      i++;
  }
  int n = points.size();
  // get the maximum gap between the x coordinates
  vector<point>::const_iterator i = points.begin();
  int mgap = i->x;
  for (i++; i != points.end(); i++)
    mgap = max(mgap, i->x - (i - 1)->x);
  mgap = max(mgap, l - (i - 1)->x);
  int maxr = mgap * w;
  sort(points.begin(), points.end(), upper_order);
    // sort the points in descending order of y coordinates
  for (vector<point>::const_iterator i = points.begin();
    i != points.end(); i++) {
    int tl = 0, tr = l;
    vector<point>::const_iterator j = i;
    for (j++; j != points.end(); j++)
      if (j->x > tl && j->x < tr) {
        maxr = max(maxr, (tr - tl) * (i->y - j->y));
        if (j->x > i->x)
          tr = j->x;
        else
          tl = j->x;
      }
    maxr = max(maxr, (tr - tl) * i->y);
  }
  for (vector<point>::const_reverse_iterator i = points.rbegin();
    i != points.rend(); i++) {
    int li = 0, ri = l;
    vector<point>::const_reverse_iterator j = i;
    for (j++; j != points.rend(); j++)
      // since points are sorted in descending order of y coordinates,
      // j->y >= i->y
      if (j->y > i->y) {
        if (j->x > i->x)
          ri = min(ri, j->x);
        else
          li = max(li, j->x);
      }
    maxr = max(maxr, (ri - li) * (w - i->y));
  }
  return maxr;
}

int main(int /* argc */, char** /* argv */)
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  int nr_scenarios;
  cin >> nr_scenarios;
  while (nr_scenarios--) {
    vector<point> points;
    int l, w;
    cin >> l >> w;
    while (true) {
      int k;
      cin >> k;
      if (!k) // end of a scenario
        break;
      int x, y, dx = 0, dy = 0;
      cin >> x >> y;
      if (k > 1)
        cin >> dx >> dy;
      for ( ; k; k--, x += dx, y += dy)
        points.push_back(point(x, y));
    }
    cout << maximum_empty_rectangle(l, w, points) << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

Uva 10032 - Tug of War

Accepted date: 2011-03-12
Ranking (as of 2013-10-26): 178 out of 817
Language: C++

Used sort of an incomplete Dynamic Programming to get the candidates of solutions and then Applied backtracking for the candidates.


/*
  8.6.5 Tug of War
  PC/UVa IDs: 110805/10032, Popularity: B, Success rate: low Level: 2

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

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

#ifdef DEBUG
void print_pr_people(int sum_of_weights, const vector< pair<unsigned char,
  unsigned char> >& nr_people)
{
  for (int i = 1; i <= sum_of_weights; i++)
    if (nr_people[i].first)
      cout << i << '(' << static_cast<unsigned int>(nr_people[i].first) << ' ' <<
        static_cast<unsigned int>(nr_people[i].second) << ") ";
  cout << endl;
}
#endif

int generate_nr_people(int n, const vector<int>& weights,
  vector< pair<unsigned char, unsigned char> >& nr_people)
{
/*
  While calculating each realizable team weight, 
  also record the minimum/maximum number of people whose weights are 
  added up to it.
*/
  int sum_of_weights = 0;
  for (int i = 1; i <= n; i++) {
    int w = weights[i];
    for (int j = sum_of_weights; j; j--)
      if (nr_people[j].first) {
        if (nr_people[j + w].first) {
          nr_people[j + w].first = min(nr_people[j + w].first,
            static_cast<unsigned char>(nr_people[j].first + 1));
          nr_people[j + w].second = max(nr_people[j + w].second,
            static_cast<unsigned char>(nr_people[j].second + 1));
        }
        else {
          nr_people[j + w].first = nr_people[j].first + 1;
          nr_people[j + w].second = nr_people[j].second + 1;
        }
      }
    nr_people[w].first = 1;
    if (!nr_people[w].second)
      nr_people[w].second = 1;
    sum_of_weights += w;
  }
#ifdef DEBUG
  print_pr_people(sum_of_weights, nr_people);
#endif
  return sum_of_weights;
}

bool is_valid_team_weight(int nr_one, int nr_other,
  int one_weight, int other_weight, int nr_weights,
  const vector<int>& weights, const vector< pair<unsigned char,
  unsigned char> >& nr_people)
{
  if (!nr_weights)
    return false;
  int w = one_weight - weights[nr_weights];
  if (!w) {
    if (nr_one == 1)
      return true;
    else if (nr_other > 1 && other_weight == one_weight)
      return false;
    else return is_valid_team_weight(nr_other, nr_one, other_weight, one_weight,
      nr_weights, weights, nr_people);
  }
  else if (w < 0)
    return is_valid_team_weight(nr_other, nr_one, other_weight, one_weight,
      nr_weights, weights, nr_people);
  else if (nr_people[w].first && nr_one - 1 >= nr_people[w].first &&
    nr_one - 1 <= nr_people[w].second &&
    is_valid_team_weight(nr_one - 1, nr_other, w, other_weight,
      nr_weights - 1, weights, nr_people))
    return true;
  else {
    if (!(w = other_weight - weights[nr_weights]))
      return (nr_other == 1) ? true : false;
    else if (w < 0)
      return false;
    else if (nr_people[w].first && nr_other - 1 >= nr_people[w].first &&
      nr_other - 1 <= nr_people[w].second &&
      is_valid_team_weight(nr_one, nr_other - 1, one_weight, w,
        nr_weights - 1, weights, nr_people))
      return true;
    else
      return false;
  }
}

pair<int, int> find_minimum_team_weight_pair(int n, int sum_of_weights,
  const vector<int>& weights, const vector< pair<unsigned char,
  unsigned char> >& nr_people)
{
  int nr_one_max = n / 2, nr_other_max = 0; // max. number of people for a team
  if (n & 1)
    nr_other_max = nr_one_max + 1;
  int i = sum_of_weights / 2;
  for ( ; ; i--) {
    int nr_one = nr_people[i].first, nr_other =
      nr_people[sum_of_weights - i].first;
    if (nr_one && nr_other) {
      if (n & 1) {
        if (nr_one < nr_other_max && nr_other < nr_other_max) {
          if (is_valid_team_weight(nr_other_max, nr_one_max, sum_of_weights - i,
            i, n, weights, nr_people) ||
            is_valid_team_weight(nr_other_max, nr_one_max, i, sum_of_weights - i,
              n, weights, nr_people))
              break;
        }
        else if (nr_one == nr_other_max) {
          if (is_valid_team_weight(nr_other_max, nr_one_max, i,
            sum_of_weights - i, n, weights, nr_people))
            break;
        }
        else if (nr_other == nr_other_max) {
          if (is_valid_team_weight(nr_other_max, nr_one_max, sum_of_weights - i,
            i, n, weights, nr_people))
            break;
        }
      }
      else {
        if (nr_one <= nr_one_max && nr_other <= nr_one_max) {
          if (is_valid_team_weight(nr_one_max, nr_one_max, sum_of_weights - i,
            i, n, weights, nr_people) ||
            is_valid_team_weight(nr_one_max, nr_one_max, i, sum_of_weights - i,
            n, weights, nr_people))
            break;
        }
      }
    }
  }
  return make_pair(i, sum_of_weights - i);
}

int main(int /* argc */, char** /* argv */)
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  int cases; // number of test cases
  cin >> cases;
  while (cases--) {
    int n;
    cin >> n; // number of people
    vector<int> weights(n + 1); // vector of weights
    weights[0] = 0;
    for (int i = 1; i <= n; i++)
      cin >> weights[i];
    if (n < 2)
      cout << "0 " << weights[n] << endl;
    else {
      sort(weights.begin() + 1, weights.end());
      int sum_of_weights = 0;
      for (int i = 1; i <= n; i++)
        sum_of_weights += weights[i];
      vector< pair<unsigned char, unsigned char> >
        nr_people(sum_of_weights + 1, make_pair(0, 0));
        //  nr_peoplei].first/second is the minimum/maximum number of people 
        // whose weights are added up to i, or 0 if no weights are added up to i
      generate_nr_people(n, weights, nr_people);
      pair<int, int> weight_pair =
        find_minimum_team_weight_pair(n, sum_of_weights, weights, nr_people);
      cout << weight_pair.first << ' ' << weight_pair.second << endl;
    }
    if (cases)
      cout << endl;
        // the output of each two consecutive cases will be separated 
        // by a blank line
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

Wednesday, October 23, 2013

UVa 10895 - Matrix Transpose

Accepted date: 2013-10-22
Ranking (as of 2013-10-22): 619 out of 722
Language: C++

/*
  UVa 10895 - Matrix Transpose

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10895_Matrix_Transpose.cpp
*/

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

const int nr_non_zero_elements_max = 1000;

struct element {
  int row_;
  int column_;
  int value_;
  bool operator<(const element& e) const {
    if (row_ < e.row_)
      return true;
    else if (row_ > e.row_)
      return false;
    else
      return column_ < e.column_;
  }
} elements[nr_non_zero_elements_max];

int main()
{
  int m, n;
  while (scanf("%d %d", &m, &n) != EOF) {
    int r, c, nr_elements = 0;
    for (r = 1; r <= m; r++) {
      int nc;
      scanf("%d", &nc);
      for (c = 0; c < nc; c++) {
        elements[nr_elements + c].column_ = r;
        scanf("%d", &elements[nr_elements + c].row_);
      }
      for (c = 0; c < nc; c++)
        scanf("%d", &elements[nr_elements + c].value_);
      nr_elements += c;
    }
    sort(elements, elements + nr_elements);
    printf("%d %d\n", n, m); 
    int cs = 0, ce = 0;
    for (r = 1; r <= n; r++) {
      for ( ; elements[ce].row_ == r; ce++)
        ;
      int nc = ce - cs;
      printf("%d", nc);
      for (c = 0; c < nc; c++)
        printf(" %d", elements[cs + c].column_);
      putchar('\n');
      for (c = 0; c < nc; c++) {
        if (c)
          putchar(' ');
        printf("%d", elements[cs + c].value_);
      }
      putchar('\n');
      cs = ce;
    }
  }
  return 0;
}

Saturday, October 19, 2013

UVa 11624 - Fire!

Accepted date: 2013-10-19
Ranking (as of 2013-10-19): 40 out of 732
Language: C++

/*
  UVa 11624 - Fire!

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11624_Fire.cpp
*/

#include <queue>
#include <utility>
#include <cstdio>
using namespace std;

const int R_max = 1000, C_max = 1000;
char maze[R_max][C_max + 1];

int bfs(int R, int C, int jr, int jc)
{
  const int nr_dirs = 4;
  int dirs[nr_dirs][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
  queue< pair<pair<int, int>, int> > q;
  q.push(make_pair(make_pair(jr, jc), 0));
  for (int r = 0; r < R; r++)
    for (int c = 0; c < C; c++)
      if (maze[r][c] == 'F')
        q.push(make_pair(make_pair(r, c), -1));
  while (!q.empty()) {
    pair<pair<int, int>, int> s = q.front(); q.pop();
    for (int i = 0; i < nr_dirs; i++) {
      int r = s.first.first + dirs[i][0], c = s.first.second + dirs[i][1];
      if (r < 0 || r >= R || c < 0 || c >= C) {
        if (maze[s.first.first][s.first.second] == 'J')
          return s.second + 1;
      }
      else if (maze[s.first.first][s.first.second] == 'J') {
        if (maze[r][c] == '.') {
          maze[r][c] = 'J';
          q.push(make_pair(make_pair(r, c), s.second + 1));
        }
      }
      else { // maze[s.first.first][s.first.second] == 'F'
        if (maze[r][c] == '.' || maze[r][c] == 'J') {
          maze[r][c] = 'F';
          q.push(make_pair(make_pair(r, c), -1));
        }
      }
    }
  }
  return -1;
}

int main()
{
  int tc;
  scanf("%d", &tc);
  while (tc--) {
    int R, C;
    scanf("%d %d", &R, &C);
    int jr = -1, jc = -1;
    for (int r = 0; r < R; r++) {
      scanf("%s", maze[r]);
      if (jr == -1) {
        for (int c = 0; c < C; c++)
          if (maze[r][c] == 'J') {
            jr = r; jc = c; break;
          }
      }
    }
    int minutes = bfs(R, C, jr, jc);
    if (minutes == -1)
      puts("IMPOSSIBLE");
    else
      printf("%d\n", minutes);
  }
  return 0;
}

Sunday, October 13, 2013

UVa 11239 - Open Source

Accepted date: 2013-10-13
Ranking (as of 2013-10-13): 194 out of 724
Language: C++

/*
  UVa 11239 - Open Source

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11239_Open_Source.cpp
*/

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

struct project {
  string name_;
  int nr_students_;

  project() : nr_students_(0) {}
  project(const string& name) : name_(name), nr_students_(0) {}

  bool operator<(const project& p) const {
    if (nr_students_ > p.nr_students_)
      return true;
    else if (nr_students_ < p.nr_students_)
      return false;
    else
      return name_ < p.name_;
  }
};

int main()
{
  bool continued = false;
  string s;
  while (true) {
    vector<project> projects;
    map<string, int> students;
    int pi;
    while (true) {
      if (!continued)
        getline(cin, s);
      else
        continued = false;
      if (s[0] == '1')
        break;
      if (isupper(s[0])) {
        pi = static_cast<int>(projects.size());
        projects.push_back(project(s));
      }
      else {
        pair< map<string, int>::iterator, bool >
          result = students.insert(make_pair(s, pi));
        if (result.second)
          projects[pi].nr_students_++;
        else if (result.first->second != pi) {
          if (result.first->second != -1) {
            projects[result.first->second].nr_students_--;
            result.first->second = -1;
          }
        }
      }
    }
    sort(projects.begin(), projects.end());
    for (vector<project>::const_iterator i = projects.begin(),
      e = projects.end(); i != e; ++i)
      cout << i->name_ << ' ' << i->nr_students_ << endl;
    getline(cin, s);
    if (s[0] == '0')
      break;
    continued = true;
  }
  return 0;
}

UVa 10920 - Spiral Tap

Accepted date: 2013-10-13
Ranking (as of 2013-10-13): 265 out of 725
Language: C++

/*
  UVa 10920 - Spiral Tap

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10920_Spiral_Tap.cpp
*/

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

int main()
{
  while (true) {
    int sz;
    long long p;
    cin >> sz >> p;
    if (!sz && !p)
      break;
    long long x = (sz + 1) / 2, y = (sz + 1) / 2;
    long long q = sqrt(static_cast<double>(p));
      // max. odd number equal to or less than sqrt(p)
    if (!(q & 1))
      q--;
    x += (q - 1) / 2; y += (q - 1) / 2;
    p -= q * q;
    if (p) {
      q++;
      if (p <= q) {
        x -= p - 1; y++;
      }
      else if (p <= q * 2) {
        x -= q - 1; y -= p - q - 1;
      }
      else if (p <= q * 3) {
        x -= q * 3 - p - 1; y -= q - 1;
      }
      else {
        x++; y -= q * 4 - p - 1;
      }
    }
    cout << "Line = " << y << ", column = " << x << ".\n";
  }
  return 0;
}

Sunday, October 6, 2013

UVa 162 - Beggar My Neighbour

Accepted date: 2013-10-06
Ranking (as of 2013-10-06): 108 out of 736
Language: C++

/*
  UVa 162 - Beggar My Neighbour

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_162_Beggar_My_Neighbour.cpp
*/

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

int face_card(char c)
{
  switch (c) {
  case 'J':
    return 1;
  case 'Q':
    return 2;
  case 'K':
    return 3;
  case 'A':
    return 4;
  default:
    return 0;
  }
}

int play(int nc, list<char>& player, list<char>& played)
{
  if (!nc)
    nc = 1;
  while (nc--) {
    if (player.empty())
      return -1;
    char c = player.front();
    player.pop_front();
    played.push_back(c);
    int fc = face_card(c);
    if (fc)
      return fc;
  }
  return 0;
}

int main()
{
  const int nr_cards = 52;
  while (true) {
    list<char> players[2], played;
      // players[0] is the non-dealer, players[1] is the dealer
      char card[2 + 1];
      scanf("%s", card);
    if (card[0] == '#')
      break;
    players[0].push_front(card[1]);
    for (int i = 1; i < nr_cards; i++) {
      scanf("%s", card);
      players[i % 2].push_front(card[1]);
    }
    bool done = false;
    int pi = 0, nc = 0;
    while (true) {
      int fc = play(nc, players[pi], played);
      pi = (pi + 1) % 2;
      if (fc == -1)
        break;
      if (!fc && nc)
        players[pi].splice(players[pi].end(), played);
      nc = fc;
    }
    printf("%d%3d\n", 2 - pi, static_cast<int>(players[pi].size()));
  }
  return 0;
}

Saturday, October 5, 2013

UVa 535 - Globetrotter

Accepted date: 2013-10-04
Ranking (as of 2013-10-05): 60 out of 791
Language: C++

/*
  UVa 535 - Globetrotter

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_535_Globetrotter.cpp
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

const double pi = 2.0 * acos(0.0);

const double sphere_radius  = 6378.0;
const int nr_cities_max = 100, nr_chars_max = 31;

struct city {
  char name_[nr_chars_max + 1];
  double latitude_, longitude_;
} cities[nr_cities_max + 1];

int compare_city(const void* i, const void* j)
{
  const city *ci = reinterpret_cast<const city*>(const_cast<void*>(i)),
    *cj = reinterpret_cast<const city*>(const_cast<void*>(j));
  return strcmp(ci->name_, cj->name_);
}

double degree_to_radian(double degree)
{
  return (pi / 180.0) * degree;
}

double great_circle_distance(double radius,
  double latitude_s, double longitude_s,
  double latitude_f, double longitude_f)
{
/*
  latitude_s/_f and longitude_s/_f are in units of radian 
  (radian = (pi / 180) * degree)
*/
  double phi = latitude_f - latitude_s, lambda = longitude_f - longitude_s;
  double delta = pow(sin(phi / 2.0), 2) +
    cos(latitude_s) * cos(latitude_f) * pow(sin(lambda / 2.0), 2);
  delta = 2 * asin(sqrt(delta));
  return radius * delta;
}

int main()
{
  int n = 0;
  while (true) {
    scanf("%s %lf %lf",
      cities[n].name_, &cities[n].latitude_, &cities[n].longitude_);
    if (!strcmp(cities[n].name_, "#"))
      break;
    cities[n].latitude_ = degree_to_radian(cities[n].latitude_);
    cities[n].longitude_ = degree_to_radian(cities[n].longitude_);
    n++;
  }
  qsort(cities, n, sizeof(city), compare_city);
  while (true) {
    city ca, cb;
    scanf("%s %s", ca.name_, cb.name_);
    if (!strcmp(ca.name_, "#") && !strcmp(cb.name_, "#"))
      break;
    city *pca = reinterpret_cast<city*>(
      bsearch(&ca, cities, n, sizeof(city), compare_city)),
      *pcb = reinterpret_cast<city*>(
        bsearch(&cb, cities, n, sizeof(city), compare_city));
    printf("%s - %s\n", ca.name_, cb.name_);
    if (!pca || !pcb)
      puts("Unknown");
    else
      printf("%.0lf km\n",
        great_circle_distance(sphere_radius, pca->latitude_, pca->longitude_,
        pcb->latitude_, pcb->longitude_));
  }
  return 0;
}

Thursday, October 3, 2013

UVa 314 - Robot

Accepted date: 2013-10-03
Ranking (as of 2013-10-03): 110 out of 748
Language: C++

/*
  UVa 314 - Robot

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_314_Robot.cpp
*/

#include <queue>
#include <utility>
#include <cstdio>
using namespace std;

enum {north, south, east, west};

struct path {
  pair<int, int> pos_;
  int dir_;
  int seconds_;
};

const int m_max = 50, n_max = 50;
bool store[m_max][n_max], visited[m_max][n_max][west - north + 1];

int go_forward(int m, int n, int step, const path& p, queue<path>& q)
{
  path np;
  switch (p.dir_) {
  case north:
    if (p.pos_.first - step - 1 < 0 ||
      store[p.pos_.first - step - 1][p.pos_.second - 1] ||
      store[p.pos_.first - step - 1][p.pos_.second])
      return -1;
    np.pos_ = make_pair(p.pos_.first - step, p.pos_.second);
    break;
  case south:
    if (p.pos_.first + step >= m ||
      store[p.pos_.first + step][p.pos_.second - 1] ||
      store[p.pos_.first + step][p.pos_.second])
      return -1;
    np.pos_ = make_pair(p.pos_.first + step, p.pos_.second);
    break;
  case east:
    if (p.pos_.second + step >= n ||
      store[p.pos_.first][p.pos_.second + step] ||
      store[p.pos_.first - 1][p.pos_.second + step])
      return -1;
    np.pos_ = make_pair(p.pos_.first, p.pos_.second + step);
    break;
  default:
    if (p.pos_.second - step - 1 < 0 ||
      store[p.pos_.first][p.pos_.second  - step - 1] ||
      store[p.pos_.first - 1][p.pos_.second - step - 1])
      return -1;
    np.pos_ = make_pair(p.pos_.first, p.pos_.second - step);
    break;
  }
  np.dir_ = p.dir_;
  if (visited[np.pos_.first][np.pos_.second][np.dir_])
    return 0;
  np.seconds_ = p.seconds_ + 1;
  visited[np.pos_.first][np.pos_.second][np.dir_] = true;
  q.push(np);
  return 1;
}

bool turn(bool right, const path &p, queue<path>& q)
{
  path np;
  switch (p.dir_) {
  case north:
    np.dir_ = (right) ? east : west; break;
  case south:
    np.dir_ = (right) ? west : east; break;
  case east:
    np.dir_ = (right) ? south : north; break;
  default:
    np.dir_ = (right) ? north : south; break;
  }
  if (visited[p.pos_.first][p.pos_.second][np.dir_])
    return false;
  np.pos_ = p.pos_; np.seconds_ = p.seconds_ + 1;
  visited[np.pos_.first][np.pos_.second][np.dir_] = true;
  q.push(np);
  return true;
}

int bfs(int m, int n, const pair<int, int>&b, const pair<int, int>&e, int dir)
{
  path p;
  p.pos_ = b; p.dir_ = dir; p.seconds_ = 0;
  queue<path> q;
  visited[b.first][b.second][dir] = true;
  q.push(p);
  while (!q.empty()) {
    path p = q.front(); q.pop();
#ifdef DEBUG
    printf("%d %d %d, %d\n", p.pos_.first, p.pos_.second, p.dir_, p.seconds_);
#endif
    if (p.pos_ == e)
      return p.seconds_;
    turn(false, p, q); // turn left
    turn(true, p, q); // turn right
    for (int step = 1; step <= 3; step++)
      if (go_forward(m, n, step, p, q) == -1)
        break;
  }
  return -1;
}

int main()
{
  while (true) {
    int m, n;
    scanf("%d %d", &m, &n);
    if (!m && !n)
      break;
    for (int i = 0; i < m; i++)
      for (int j = 0; j < n; j++) {
        visited[i][j][north] = visited[i][j][south] =
          visited[i][j][east] = visited[i][j][west] = false;
        int zeor_or_one;
        scanf("%d", &zeor_or_one);
        store[i][j] = zeor_or_one;
      }
    pair<int, int> b, e;
    char s[8];
    scanf("%d %d %d %d %s", &b.first, &b.second, &e.first, &e.second, s);
    int dir;
    switch (s[0]) {
    case 'n':
      dir = north; break;
    case 's':
      dir = south; break;
    case 'e':
      dir = east; break;
    default:
      dir = west; break;
    }
    printf("%d\n", bfs(m, n, b, e, dir));
  }
  return 0;
}

Wednesday, October 2, 2013

UVa 10393 - The One-Handed Typist

Accepted date: 2013-10-02
Ranking (as of 2013-10-02): 425 out of 742
Language: C++

/*
  UVa 10393 - The One-Handed Typist

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10393_The_One_Handed_Typist.cpp
*/

#include <cstdio>
#include <cstdlib>
#include <cstring>

const int nr_letters = 128;
const char* keyboard_chars[] = 
  {"", "qaz", "wsx", "edc", "rfvtgb", "", "", "yhnujm", "ik,", "ol.", "p;/"};

const int nr_chars_max = 63, n_max = 1000;

struct word {
  int length_;
  char s_[nr_chars_max + 1];
} words[n_max];

int compare_word(const void* i, const void* j)
{
  const word *wi = reinterpret_cast<const word*>(const_cast<void*>(i)),
    *wj = reinterpret_cast<const word*>(const_cast<void*>(j));
  if (wi->length_ > wj->length_)
    return -1;
  else if (wi->length_ < wj->length_)
    return 1;
  else
    return strcmp(wi->s_, wj->s_);
}

int main()
{
  bool letters[nr_letters]; // letters[i] is true if a letter i can be typed
  int i, j, f, n, m, mm, max_length;
  const char* p;
  while (scanf("%d %d", &f, &n) != EOF) {
    memset(letters, -1, sizeof(letters));
    while (f--) {
      scanf("%d", &i);
      for (p = keyboard_chars[i]; *p; p++)
        letters[*p] = false;
    }
    m = mm = max_length = 0;
    while (n--) {
      scanf("%s", words[m].s_);
      for (p = words[m].s_; *p; p++)
        if (!letters[*p])
          break;
      if (!*p && p - words[m].s_) {
        words[m].length_ = p - words[m].s_;
        if (words[m].length_ > max_length) {
          max_length = words[m].length_;
          mm = 1;
        }
        else if (words[m].length_ == max_length)
          mm++;
        m++;
      }
    }
    qsort(words, m, sizeof(word), compare_word);
#ifdef DEBUG
    for (i = 0; i < m; i++)
      printf("%s%c", words[i].s_, ((i == m - 1) ? '\n' : ' '));
#endif
    for (i = 0, j = mm - 1; i < j; i++) // remove duplicated words
      if (!strcmp(words[i].s_, words[i + 1].s_)) {
        words[i].s_[0] = '\0';
        mm--;
      }
    printf("%d\n", mm);
    for (i = 0, j = 0; j < mm; i++) 
      if (words[i].s_[0]) {
        printf("%s\n", words[i].s_);
        j++;
      }
  }
  return 0;
}

Sunday, September 29, 2013

UVa 11056 - Formula 1

Accepted date: 2013-09-29
Ranking (as of 2013-09-29): 110 out of 746
Language: C++

/*
  UVa 11056 - Formula 1

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11056_Formula_1.cpp
*/

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

#ifdef ONLINE_JUDGE
#define _stricmp strcasecmp
#endif

const int nr_name_chars_max = 31, nr_pilots_max = 100;

struct pilot {
  char name_[nr_name_chars_max + 1];
  int lap_;

  bool operator<(const pilot& p) const;
} pilots[nr_pilots_max];

bool pilot::operator<(const pilot& p) const
{
  if (lap_ < p.lap_)
    return true;
  else if (lap_ > p.lap_)
    return false;
  else
    return _stricmp(name_, p.name_) < 0;
}

int main()
{
  int n;
  while (scanf("%d", &n) != EOF) {
    for (int i = 0; i < n; i++) {
      int m, s, ms;
      scanf("%s %*s %d %*s %d %*s %d %*s", pilots[i].name_, &m, &s, &ms);
      pilots[i].lap_ = m * 60000 + s * 1000 + ms;
#ifdef DEBUG
      printf("%s %d\n", pilots[i].name_, pilots[i].lap_);
#endif
    }
    sort(pilots, pilots + n);
    for (int i = 0, r = 1; i < n; r++) {
      printf("Row %d\n", r);
      puts(pilots[i++].name_);
      if (i < n)
        puts(pilots[i++].name_);
    }
    putchar('\n');
  }
  return 0;
}

Monday, September 23, 2013

UVa 245 - Uncompress

Accepted date: 2013-09-23
Ranking (as of 2013-09-23): 19 out of 775
Language: C++

/*
  UVa 245 - Uncompress

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_245_Uncompress.cpp
*/

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

int main()
{
  int n = 0; // number of words
  vector<char*> words; // word list
  while (true) {
    string s;
    getline(cin, s);
    if (s[0] == '0')
      break;
    for (const char *p = s.c_str(), *q = s.c_str(); ; ) {
      if (isdigit(*p)) {
        int i = *p - '0';
        for (p++; isdigit(*p); p++) {
          i *= 10;
          i += *p - '0';
        }
        q = p;
        i--;
        char* r = words[n - 1 - i];
        cout << r;
        // move the word to the back of the list
        memmove(&words[n - 1 - i], &words[n - i], sizeof(char*) * i);
        words[n - 1] = r;
      }
      else {
        if (*p)
          cout << *p;
        if (isalpha(*p))
          p++;
        else {
          if (p - q) {
            // add a word at the back of the list
            char* t = new char[p - q + 1];
            memcpy(t, q, p - q);
            *(t + (p - q)) = '\0';
            words.push_back(strdup(t));
            n++;
            q = p;
          }
          if (*p) {
            p++; q++;
          }
          else // end of line
            break;
        }
      }
    }
    cout << endl;
  }
  return 0;
}

Sunday, September 22, 2013

UVa 168 - Theseus and the Minotaur

Accepted date: 2013-09-21
Ranking (as of 2013-09-22): 22 out of 789
Language: C++

/*
  UVa 168 - Theseus and the Minotaur

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_168_Theseus_and_the_Minotaur.cpp
*/

#include <cstdio>

const int nr_letters = 26;

struct cavern {
  int reachables_[nr_letters + 1];
  bool candle_;
} caverns[nr_letters];

int main()
{
  const int nr_chars_max = 255;
  char s[nr_chars_max + 1];
  while (true) {
    scanf("%s", s);
    if (s[0] == '#')
      break;
    cavern caverns[nr_letters];
    for (int i = 0; i < nr_letters; i++) {
      caverns[i].reachables_[0] = -1;
      caverns[i].candle_ = false;
    }
    for (const char* p = s; *p; p++) {
      int i = *p++ - 'A', j = 0;
      for (p++; *p >= 'A' && *p <= 'Z'; p++)
        caverns[i].reachables_[j++] = *p - 'A';
      caverns[i].reachables_[j] = -1; // terminator
    }
    char mc[1 + 1], tc[1 + 1];
    int mi, pmi, k, ki = 1;
    scanf("%s %s %d", mc, tc, &k);
    mi = mc[0] - 'A', pmi = tc[0] - 'A';
    int np = 0, passed[nr_letters];
    while (true) {
#ifdef DEBUG
      printf("%d %d\n", pmi, mi);
#endif
      if (pmi == mi) {
        if (!caverns[mi].candle_)
          passed[np++] = mi;
        break;
      }
      if (ki == k) {
        ki = 0;
#ifdef DEBUG
        printf("%d\n", mi);
#endif
        caverns[mi].candle_ = true;
        passed[np++] = mi;
      }
      const int* pc;
      for (pc = caverns[mi].reachables_; *pc != -1; pc++)
        if (*pc != pmi && !caverns[*pc].candle_)
          break;
      if (*pc == -1) {
        if (!caverns[mi].candle_)
          passed[np++] = mi;
        break;
      }
      else {
        pmi = mi;
        mi = *pc;
        ki++;
      }
    }
    for (int i = 0; i < np; i++) {
      if (i)
        putchar(' ');
      if (i == np - 1)
        putchar('/');
      putchar(passed[i] + 'A');
    }
    putchar('\n');
  }
  return 0;
}

Monday, September 16, 2013

UVa 10287 - Gifts in a Hexagonal Box

Accepted date: 2013-09-16
Ranking (as of 2013-09-16): 143 out of 765
Language: C++

/*
  UVa 10287 - Gifts in a Hexagonal Box

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10287_Gifts_in_a_Hexagonal_Box.cpp
*/

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

int main()
{
  const double c1 = sqrt(3.0) / 2.0, c2 = sqrt(3.0) / (2.0 + sqrt(3.0)),
    c3 = sqrt(3.0) / 4.0, c4 = (6.0 * sqrt(21.0) - 21.0) / (10.0 * sqrt(3.0));
  double s;
  while (cin >> s)
    cout << fixed <<
      setprecision(10) << c1 * s << ' ' << setprecision(10) << c2 * s << ' ' <<
      setprecision(10) << c3 * s << ' ' << setprecision(10) << c4 * s << endl;
  return 0;
}

Sunday, September 15, 2013

UVa 462 - Bridge Hand Evaluator

Accepted date: 2013-09-15
Ranking (as of 2013-09-15): 118 out of 765
Language: C++

/*
  UVa 462 - Bridge Hand Evaluator

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_462_Bridge_Hand_Evaluator.cpp
*/

#include <cstdio>

enum {spade, heart, diamond, club};
const int nr_suits = club + 1, nr_ranks = 13;

struct suit {
  int nr_;
  bool ace_, jack_, queen_, king_;
} suits[nr_suits];

void initialize_suits()
{
  for (int i = 0; i < nr_suits; i++) {
    suits[i].nr_ = 0;
    suits[i].ace_ = suits[i].jack_ = suits[i].queen_ = suits[i].king_ = false;
  }
}

bool read_cards()
{
  char card[2 + 1];
  int si;
  for (int i = 0; i < nr_ranks; i++) {
    if (scanf("%s", card) == EOF)
      return false;
    switch (card[1]) {
    case 'S':
      si = spade; break;
    case 'H':
      si = heart; break;
    case 'D':
      si = diamond; break;
    default:
      si = club; break;
    }
    suits[si].nr_++;
    switch (card[0]) {
    case 'A':
      suits[si].ace_ = true; break;
    case 'J':
      suits[si].jack_ = true; break;
    case 'Q':
      suits[si].queen_ = true; break;
    case 'K':
      suits[si].king_ = true; break;
    default:
      break;
    }
  }
  return true;
}

int calculate_points_1_4()
{
  int points = 0;
  for (int si = 0; si < nr_suits; si++) {
    const suit& s = suits[si];
    if (s.ace_)
      points += 4;
    if (s.king_)
      points += (s.nr_ < 2) ? 2 : 3;
    if (s.queen_)
      points += (s.nr_ < 3) ? 1 : 2;
    if (s.jack_ && s.nr_ > 3)
      points++;
  }
  return points;
}

int calculate_points_5_7()
{
  int points = 0;
  for (int si = 0; si < nr_suits; si++) {
    const suit& s = suits[si];
    if (s.nr_ == 2)
      points++;
    else if (s.nr_ < 2)
      points += 2;
  }
  return points;
}

bool is_no_trump(int points)
{
  if (points < 16)
    return false;
  for (int si = 0; si < nr_suits; si++) {
    const suit& s = suits[si];
    if (s.ace_ || s.king_ && s.nr_ > 1 ||
      s.queen_ && s.nr_ > 2) // suit is stopped
      ;
    else
      return false;
  }
  return true;
}

char bid()
{
  const char ss[] = "SHDC";
  int max_si, max_nr = 0;
  for (int si = 0; si < nr_suits; si++)
    if (suits[si].nr_ > max_nr) {
      max_si = si;
      max_nr = suits[si].nr_;
    }
  return ss[max_si];
}

int main()
{
  while (true) {
    initialize_suits();
    if (!read_cards())
      break;
    int points = calculate_points_1_4();
    if (is_no_trump(points))
      puts("BID NO-TRUMP");
    else {
      points += calculate_points_5_7();
      if (points < 14)
        puts("PASS");
      else
        printf("BID %c\n", bid());
    }
  }
  return 0;
}

UVa 10284 - Chessboard in FEN

Accepted date: 2013-09-15
Ranking (as of 2013-09-15): 160 out of 757
Language: C++

/*
  UVa 10284 - Chessboard in FEN

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10284_Chessboard_in_FEN.cpp
*/

#include <cstdio>
#include <cstring>
#include <cctype>

const int nr_rows = 8, nr_columns = 8;
char chessboard[nr_rows][nr_columns], fen[nr_rows * (nr_columns + 1) + 1];

bool attack(int r, int c)
{
  if (r < 0 || r >= nr_rows || c < 0 || c >= nr_columns ||
    isalpha(chessboard[r][c]))
    return false;
  chessboard[r][c] = '+';
  return true;
}

void king_attack(int r, int c)
{
  for (int ri = r - 1; ri <= r + 1; ri++)
    for (int ci = c - 1; ci <= c + 1; ci++)
      if (ri != r || ci != c)
        attack(ri, ci);
}

void rook_attack(int r, int c)
{
  int ri, ci;
  for (ri = r - 1; ; ri--)
    if (!attack(ri, c))
      break;
  for (ri = r + 1; ; ri++)
    if (!attack(ri, c))
      break;
  for (ci = c - 1; ; ci--)
    if (!attack(r, ci))
      break;
  for (ci = c + 1; ; ci++)
    if (!attack(r, ci))
      break;
}

void bishop_attack(int r, int c)
{
  int ri, ci;
  for (ri = r - 1, ci = c - 1; ; ri--, ci--)
    if (!attack(ri, ci))
      break;
  for (ri = r - 1, ci = c + 1; ; ri--, ci++)
    if (!attack(ri, ci))
      break;
  for (ri = r + 1, ci = c - 1; ; ri++, ci--)
    if (!attack(ri, ci))
      break;
  for (ri = r + 1, ci = c + 1; ; ri++, ci++)
    if (!attack(ri, ci))
      break;
}

void knight_attack(int r, int c)
{
  attack(r - 2, c - 1);
  attack(r - 2, c + 1);
  attack(r - 1, c - 2);
  attack(r - 1, c + 2);
  attack(r + 1, c - 2);
  attack(r + 1, c + 2);
  attack(r + 2, c - 1);
  attack(r + 2, c + 1);
}

#ifdef DEBUG
void print_chessboard()
{
  for (int r = 0; r < nr_rows; r++)
    for (int c = 0; c < nr_columns; c++)
    printf("%c%c", chessboard[r][c], ((c == nr_columns - 1) ? '\n' : ' '));
}
#endif

int main()
{
  while (scanf("%s", fen) != EOF) {
    memset(chessboard, '-', sizeof(chessboard));
    int r = 0, c = 0;
    for (const char* p = fen; *p; p++) {
      if (*p == '/') {
        r++; c = 0;
      }
      else if (isdigit(*p))
        c += *p - '0';
      else
        chessboard[r][c++] = *p;
    }
    for (r = 0; r < nr_rows; r++)
      for (c = 0; c < nr_columns; c++) {
        switch (chessboard[r][c]) {
        case 'k': case 'K':
          king_attack(r, c);
          break;
        case 'q': case 'Q':
          rook_attack(r, c);
          bishop_attack(r, c);
          break;
        case 'b': case 'B':
          bishop_attack(r, c);
          break;
        case 'n': case 'N':
          knight_attack(r, c);
          break;
        case 'r': case 'R':
          rook_attack(r, c);
          break;
        case 'p':
          attack(r + 1, c - 1);
          attack(r + 1, c + 1);
          break;
        case 'P':
          attack(r - 1, c - 1);
          attack(r - 1, c + 1);
          break;
        }
#ifdef DEBUG
        if (isalpha(chessboard[r][c])) {
          printf("%d %d: %c\n", r, c, chessboard[r][c]);
          print_chessboard();
        }
#endif
      }
    int nr_unoccupied = 0;
    for (r = 0; r < nr_rows; r++)
      for (c = 0; c < nr_columns; c++)
        if (chessboard[r][c] == '-')
          nr_unoccupied++;
    printf("%d\n", nr_unoccupied);
  }
  return 0;
}

Saturday, September 14, 2013

UVa 10500 - Robot maps

Accepted date: 2013-09-14
Language: C++

/*
  UVa 10500 - Robot maps

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_10500_Robot_maps.cpp
*/

#include <iostream>
using namespace std;

const int n_max = 10, m_max = 10;
char map[n_max + 1][m_max + 1], robot_map[n_max +1][m_max + 1];
bool visited[n_max + 1][m_max + 1];

int dfs(int n, int m, int px, int py)
{
  const int dirs[][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
  const size_t nr_dirs = sizeof(dirs) / sizeof(dirs[0]);

  visited[px][py] = true;
  for (size_t i = 0; i < nr_dirs; i++) {
    int x = px + dirs[i][0], y = py + dirs[i][1];
    if (x >= 1 && x <= n && y >= 1 && y <= m)
      robot_map[x][y] = map[x][y];
  }
  int nr_visited = 0;
  for (size_t i = 0; i < nr_dirs; i++) {
    int x = px + dirs[i][0], y = py + dirs[i][1];
    if (x >= 1 && x <= n && y >= 1 && y <= m &&
      map[x][y] == '0' && !visited[x][y]) {
      nr_visited = 1 + dfs(n, m, x, y);
      break;
    }
  }
  return nr_visited;
}

int main()
{
  while (true) {
    int n, m;
    cin >> n >> m;
    if (!n && !m)
      break;
    int x_ini, y_ini;
    cin >> x_ini >> y_ini;
    for (int x = 1; x <= n; x++)
      for (int y = 1; y <= m; y++) {
        visited[x][y] = false;
        robot_map[x][y] = '?';
        cin >> map[x][y];
      }
    robot_map[x_ini][y_ini] = '0';
    int nr_movements = dfs(n, m, x_ini, y_ini);
    cout << endl;
    for (int y = 1; y <= m; y++)
      cout << "|---";
    cout << "|\n";
    for (int x = 1; x <= n; x++) {
      for (int y = 1; y <= m; y++)
        cout << "| " << robot_map[x][y] << ' ';
      cout << "|\n";
      for (int y = 1; y <= m; y++)
        cout << "|---";
      cout << "|\n";
    }
    cout << "\nNUMBER OF MOVEMENTS: " << nr_movements << endl;
  }
  return 0;
}

UVa 416 - LED Test

Accepted date: 2013-09-14
Ranking (as of 2013-09-14): 312 out of 754
Language: C++

/*
  UVa 416 - LED Test

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_416_LED_Test.cpp
*/

#include <cstdio>

const unsigned char leds[] =
  {0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b};
const int n_max = sizeof(leds);

unsigned char s_to_sequence(const char* s)
{
  unsigned char sq = 0, b = 0x40;
  do {
    if (*s++ == 'Y')
      sq |= b;
    b >>= 1;
  } while (b);
  return sq;
}

bool match_sequence(int n, unsigned char sequence[])
{
  for (int ns = n_max; ns >= n; ns--) {
    bool match = true;
    unsigned char not_burned = 0x7f;
    for (int i = 1; i <= n; i++) {
      unsigned char led = leds[ns - i];
      led &= not_burned;
      unsigned char diff = led ^ sequence[i - 1];
      unsigned char db = diff, lb = led;
      for ( ; db; db >>= 1, lb >>= 1)
        if (db & 1 && !(lb & 1))
          break; // no burned-out segments will recover
      if (db) {
        match = false; break;
      }
      not_burned &= ~diff;
    }
    if (match)
      return true;
  }
  return false;
}

int main()
{
  while (true) {
    int n;
    scanf("%d", &n);
    if (!n)
      break;
    unsigned char sequence[n_max];
    for (int i = 0; i < n; i++) {
      char s[7 + 1];
      scanf("%s", s);
      sequence[i] = s_to_sequence(s);
    }
    if (match_sequence(n, sequence))
      puts("MATCH");
    else
      puts("MISMATCH");
  }
  return 0;
}

UVa 10493 - Cats, with or without Hats

Accepted date: 2013-09-13
Ranking (as of 2013-09-14): 496 out of 762
Language: C++

/*
  UVa 10493 - Cats, with or without Hats

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

#include <iostream>
using namespace std;

int how_many_cats(int n, int m)
{
  if (n == 1)
    return (m == 1) ? -1 : 0;
  if (m == 1)
    return 1;
  int nc = m;
  while (m > 1) {
    if (m < n)
      return 0;
    nc += m / n;
    m = m / n + m % n;
  }
  return nc;
}

int main()
{
  while (true) {
    int n, m;
    cin >> n >> m;
    if (!n)
      break;
    cout << n << ' ' << m << ' ';
    int nc = how_many_cats(n, m);
    if (nc == -1)
      cout << "Multiple\n";
    else if (!nc)
      cout << "Impossible\n";
    else
      cout << nc << endl;
  }
  return 0;
}

Sunday, September 8, 2013

UVa 11384 - Help is needed for Dexter

Accepted date: 2013-09-07
Ranking (as of 2013-09-08): 672 out of 764
Language: C++

/*
  UVa 11384 - Help is needed for Dexter

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_11384_Help_is_needed_for_Dexter.cpp
*/

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

int main()
{
  const double log2 = log(2.0);
  int n;
  while (cin >> n)
    cout << static_cast<int>(log(static_cast<double>(n)) / log2) + 1 << endl;
      // log2(n) + 1
  return 0;
}

Saturday, August 31, 2013

UVa 616 - Coconuts, Revisited

Accepted date: 2013-08-31
Ranking (as of 2013-08-31): 177 out of 806
Language: C++

/*
  UVa 616 - Coconuts, Revisited

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_616_Coconuts_Revisited.cpp
*/

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

/*
  Number of coconuts = (1 + n * k) * n^n  - (n - 1) for n odd
                     = (n - 1 + n * k) * n^n - (n - 1) for n even
*/

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

const int n_max = 11;
long long pow_ns[n_max + 1]; // pow_ns[i] is pow(i, i)
long long min_coconuts[n_max + 1];
  // min_coconuts[i] is the minimum number of coconuts for i

bool monkey_coconuts(long long c, int n)
{
  c += n - 1;
  if (c % pow_ns[n])
    return false;
  c /= pow_ns[n];
  if (n & 1)
    c--;
  else
    c -= n - 1;
  return (c % n) ? false : true;
}

int main()
{
  for (int i = 2; i <= n_max; i++) {
    pow_ns[i] = static_cast<long long>(
      pow(static_cast<double>(i), static_cast<double>(i)));
    if (i & 1)
      min_coconuts[i] = pow_ns[i] - (i - 1);
    else
      min_coconuts[i] = pow_ns[i] * (i - 1) - (i - 1);
#ifdef DEBUG
    cout << min_coconuts[i] << endl;
#endif
  }
  while (true) {
    long long c;
    cin >> c;
    if (c < 0)
      break;
    int n;
    for (n = 2; n <= n_max; n++)
      if (c < min_coconuts[n])
        break;
    for ( ; n > 1; n--)
      if (monkey_coconuts(c, n))
        break;
    cout << c << " coconuts, ";
    if (n == 1)
      cout << "no solution\n";
    else
      cout << n << " people and 1 monkey\n";
  }
  return 0;
}

UVa 556 - Amazing

Accepted date: 2013-08-26
Ranking (as of 2013-08-31): 690 out of 811
Language: C++

/*
  UVa 556 - Amazing

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_556_Amazing.cpp
*/

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

const int nr_visited = 5;
enum {north, south, east, west};

int turn_right(int b, int w, vector< vector<char> >& maze, int dir, int i, int j)
{
  int wi, wj;
  switch (dir) {
  case north:
    j++; wi = i + 1; wj = j; break;
  case south:
    j--; wi = i - 1; wj = j; break;
  case east:
    i++; wi = i; wj = j - 1; break;
  case west:
    i--; wi = i; wj = j + 1; break;
  }
  if (i < 0 || i >= b || j < 0 || j >= w || maze[i][j] == '1')
    return dir;
  if (wi < 0 || wi >= b || wj < 0 || wj >= w || maze[wi][wj] == '1') {
    switch (dir) {
    case north:
      dir = east; break;
    case south:
      dir = west; break;
    case east:
      dir = south; break;
    case west:
      dir = north; break;
    }
  }
  return dir;
}

int turn_left(int dir)
{
  switch (dir) {
  case north:
    dir = west; break;
  case south:
    dir = east; break;
  case east:
    dir = north; break;
  case west:
    dir = south; break;
  }
  return dir;
}

bool step_forward(int b, int w, vector< vector<char> >& maze,
  int dir, int& i, int& j)
{
  int ni = i, nj = j;
  switch (dir) {
  case north:
    ni--; break;
  case south:
    ni++; break;
  case east:
    nj++; break;
  case west:
    nj--; break;
  }
  if (ni < 0 || ni >= b || nj < 0 || nj >= w || maze[ni][nj] == '1')
    return false;
  i = ni; j = nj;
  return true;
}

int main()
{
  while (true) {
    int b, w;
    cin >> b >> w;
    if (!b && !w)
      break;
    vector< vector<char> > maze(b, vector<char>(w));
    vector< vector<int> > visited(b, vector<int>(w, 0));
    for (int i = 0; i < b; i++)
      for (int j = 0; j < w; j++)
        cin >> maze[i][j];
    int si = b - 1, sj = 0, i = b - 1, j = 0, dir = east;
    vector<int> visited_total(nr_visited, 0);
    while (true) {
      dir = turn_right(b, w, maze, dir, i, j);
      if (step_forward(b, w, maze, dir, i, j)) {
        visited[i][j]++;
        if (i == si && j == sj)
          break;
      }
      else
        dir = turn_left(dir);
    }
    for (int i = 0; i < b; i++)
      for (int j = 0; j < w; j++)
        if (maze[i][j] == '0' && visited[i][j] < nr_visited)
          visited_total[visited[i][j]]++;
    for (int i = 0; i < nr_visited; i++)
      cout << setfill(' ') << setw(3) << visited_total[i];
    cout << endl;
  }
  return 0;
}

Wednesday, August 14, 2013

UVa 10117 - Nice Milk

Accepted date: 2011-05-30
Language: C++

/*
  14.7.8 Nice Milk
  PC/UVa IDs: 111408/10117, Popularity: C, Success rate: low Level: 4

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

/*
  Do a backtrack.
  For each iteration:
    Starting with the original points of the polygon,
      choose a pair of points k-times.
    For each iteration with a pair of points p1, p2:
      Get a directed dipped line that is on the left side of 
        a vector from p1 to p2.
        The line has the same direction as the vector from p1 to p2.
      Get the points that the dipped line intersects with other line 
       segments of the polygon, 
      and add them between the points in which the line intersects.
      Iterate all of the points of the polygon and remove the points 
        that are on the right side of the line.
    Calculate the area of polygon in which some points are replaced by 
      the above process, and 
    record the minimum area.
*/

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cfloat>
#include <cmath>
#ifdef __ELAPSED_TIME__
#include <ctime>
#endif
using namespace std;

#define EPSILON FLT_EPSILON /* DBL_EPSILON */

const double pi = 2.0 * acos(0.0); // 3.14159265358979323846

struct point {
  double x, y;

  point() : x(0.0), y(0.0) {}
  point(double _x, double _y) : x(_x), y(_y) {}
  point(const point &p) : x(p.x), y(p.y) {}
  bool operator==(const point& p) const
    {return fabs(x - p.x) <= EPSILON && fabs(y - p.y) <= EPSILON;}
};

struct line {
  double a; // x-coefficient
  double b; // y-coefficient
  double c; // constant term
};

struct line_segment {
  point p1, p2;
  line_segment(const point& _p1, const point& _p2) : p1(_p1), p2(_p2) {}
};

double signed_triangle_area(const point& a, const point& b, const point& c)
{
  return (a.x * b.y - a.y * b.x + a.y * c.x -
    a.x * c.y + b.x * c.y - c.x * b.y) / 2.0;
}

bool ccw(const point& a, const point& b, const point& c)
{
  // see if the point c is to the left of a -> b
  // (or, a - b - c are counterclockwise)
  return signed_triangle_area(a, b, c) > EPSILON;
}

void points_to_line(const point& p1, const point& p2, line& l)
{
  if (fabs(p1.x - p2.x) <= EPSILON) {
    l.a = 1; l.b = 0; l.c = -p1.x;
  }
  else {
    l.b = 1;
    l.a = -(p1.y - p2.y)/(p1.x - p2.x);
    l.c = -(l.a * p1.x) - l.b * p1.y;
  }
}

bool parallelQ(const line& l1, const line& l2)
{
  return fabs(l1.a - l2.a) <= EPSILON && fabs(l1.b - l2.b) <= EPSILON;
}

bool same_lineQ(const line& l1, const line& l2)
{
  return parallelQ(l1, l2) && fabs(l1.c - l2.c) <= EPSILON;
}

bool point_in_box(const point& p, const point& b1, const point& b2)
{
  return p.x >= min(b1.x, b2.x) - EPSILON && p.x <= max(b1.x, b2.x) + EPSILON &&
    p.y >= min(b1.y, b2.y)- EPSILON && p.y <= max(b1.y, b2.y) + EPSILON;
}

bool intersection_point(const line& l1, const line& l2, point& p)
{
  if (same_lineQ(l1, l2)) {
#ifdef DEBUG
    printf("Warning: Identical lines, all points intersect.\n");
#endif
    return false;
  }

  if (parallelQ(l1, l2)) {
#ifdef DEBUG
    printf("Error: Distinct parallel lines do not intersect.\n");
#endif
    return false;
  }

  p.x = (l2.b * l1.c - l1.b * l2.c) / (l2.a * l1.b - l1.a * l2.b);

  if (fabs(l1.b) > EPSILON) // test for vertical line
    p.y = - (l1.a * p.x + l1.c) / l1.b;
  else
    p.y = - (l2.a * p.x + l2.c) / l2.b;
  return true;
}

bool line_segments_intersect(const line_segment& s, const line& l, point& p)
{
  line ls;
  points_to_line(s.p1, s.p2, ls);
  if (same_lineQ(ls, l)) // overlapping or disjoint segments
    return false; 
  if (parallelQ(ls, l))
    return false;
  intersection_point(ls, l, p);
  return point_in_box(p, s.p1, s.p2);
}

double polygon_area(const vector<point>& polygon)
{
  double area = 0.0;
  for (int i = 0; i < polygon.size(); i++) {
    int j = (i + 1) % polygon.size();
    area += polygon[i].x * polygon[j].y - polygon[j].x * polygon[i].y;
  }
  return area / 2.0;
}

void get_dipped_line(int h, const point& p1, const point& p2,
  point& dp1, point& dp2, line& dl)
{
  // get the dipped points that are on the left side of the lines perpendicular 
  // to a vector from p1 to p2, and are distant from the vector by h
  double angle = atan2(p2.y - p1.y, p2.x - p1.x);
  dp1 = point(p1.x + h * cos(angle + pi / 2.0),
    p1.y + h * sin(angle + pi / 2.0));
  dp2 = point(p2.x + h * cos(angle + pi / 2.0),
    p2.y + h * sin(angle + pi / 2.0));
  points_to_line(dp1, dp2, dl);
}

void dip_bread(int h, int i, int j, const vector<point>& points,
  const vector<point>& dpoints, vector<point>& result)
{
  point dp1, dp2;
  line dl;
  get_dipped_line(h, points[i], points[j], dp1, dp2, dl);
  for (int i = 0; i < dpoints.size(); i++) {
    int j = (i + 1) % dpoints.size();
    if (!ccw(dp1, dp2, dpoints[i]))
      ;
    else
      result.push_back(dpoints[i]);
    line_segment ls(dpoints[i], dpoints[j]);
    point dp;
    if (line_segments_intersect(ls, dl, dp))
      result.push_back(dp);
  }
}

void cover_sides_of_bread_with_milk(int k, int l, int h,
  const vector<point>& points,
  vector<point>& dpoints, double& min_area)
{
  if (min_area == 0.0)
    return;
  else if (dpoints.empty())
    min_area = 0.0;
  else if (!k) {
    double area = polygon_area(dpoints);
    if (area < min_area)
      min_area = area;
  }
  else {
    for (int i = l; i < points.size(); i++) {
      int j = (i + 1) % points.size();
      vector<point> result;
      dip_bread(h, i, j, points, dpoints, result);
      cover_sides_of_bread_with_milk(k - 1, i + 1, h, points, result, min_area);
    }
  }
}

int main(int /* argc */, char** /* argv */)
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  while (true) {
    int n, k, h;
    cin >> n >> k >> h;
    if (!n && !k && !h)
      break;
    if (k > n)
      k = n;
    vector<point> points;
    for (int i = 0; i < n; i++) {
      point p;
      cin >> p.x >> p.y;
      points.push_back(p);
    }
    double area = polygon_area(points);
    double min_area = DBL_MAX;
    if (!h || !k)
      min_area = area;
    else {
      vector<point> dpoints(points);
      cover_sides_of_bread_with_milk(k, 0, h, points, dpoints, min_area);
    }
    printf("%.2f\n", area - min_area);
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10553 - Treasure Map

Accepted date: 2011-06-19
Ranking (as of 2013-08-14): 13 out of 203
Language: C++

/*
  UVa 10553 - Treasure Map

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

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cfloat>
#include <cmath>
using namespace std;

#define EPSILON FLT_EPSILON /* DBL_EPSILON */

const double pi = 2.0 * acos(0.0); // 3.14159265358979323846

struct point {
  double x, y;

  point() : x(0.0), y(0.0) {}
  point(double _x, double _y) : x(_x), y(_y) {}
  point(const point &p) : x(p.x), y(p.y) {}
  bool operator==(const point& p) const
    {return fabs(x - p.x) <= EPSILON && fabs(y - p.y) <= EPSILON;}
};

struct line {
  double a; // x-coefficient
  double b; // y-coefficient
  double c; // constant term
};

double euclidean_distance(const point& a, const point& b)
{
  double dx = a.x - b.x, dy = a.y - b.y;
  return sqrt(dx * dx + dy * dy);
}

void points_to_line(const point& p1, const point& p2, line& l)
{
  if (p1.x == p2.x) {
    l.a = 1; l.b = 0; l.c = -p1.x;
  }
  else {
    l.b = 1;
    l.a = -(p1.y - p2.y) / (p1.x - p2.x);
    l.c = -(l.a * p1.x) - l.b * p1.y;
  }
}

void point_and_slope_to_line(const point& p, double m, line& l)
{
  l.a = -m;
  l.b = 1;
  l.c = -(l.a * p.x + l.b * p.y);
}

inline bool parallelQ(const line& l1, const line& l2)
{
  return fabs(l1.a - l2.a) <= EPSILON && fabs(l1.b - l2.b) <= EPSILON;
}

inline bool same_lineQ(const line& l1, const line& l2)
{
  return parallelQ(l1, l2) && fabs(l1.c - l2.c) <= EPSILON;
}

bool intersection_point(const line& l1, const line& l2, point& p)
{
  if (same_lineQ(l1, l2)) {
#ifdef DEBUG
    printf("Warning: Identical lines, all points intersect.\n");
#endif
    return false;
  }
  if (parallelQ(l1, l2)) {
#ifdef DEBUG
    printf("Error: Distinct parallel lines do not intersect.\n");
#endif
    return false;
  }
  p.x = (l2.b * l1.c - l1.b * l2.c) / (l2.a * l1.b - l1.a * l2.b);
  if (fabs(l1.b) > EPSILON) // test for vertical line
    p.y = - (l1.a * p.x + l1.c) / l1.b;
  else
    p.y = - (l2.a * p.x + l2.c) / l2.b;
  return true;
}

bool in_range(double d, double a, double b)
{
  return d >= min(a, b) - EPSILON && d <= max(a, b) + EPSILON;
}

bool point_in_box(const point& p, const point& b1, const point& b2)
{
  return in_range(p.x, b1.x, b2.x) && in_range(p.y, b1.y, b2.y);
}

bool closest_point_from_line_segment(const point& p, const point& sp1,
  const point& sp2, point& closest_p)
{
  // get a line segment that connects sp1 and sp2
  line l;
  points_to_line(sp1, sp2, l);
  if (fabs(l.b) <= EPSILON) {  // vertical line
    if (in_range(p.y, sp1.y, sp2.y)) {
      closest_p.x = -l.c; closest_p.y = p.y;
      return true;
    }
    else
      return false;
  }
  if (fabs(l.a) <= EPSILON) {  // horizontal line
    if (in_range(p.x, sp1.x, sp2.x)) {
      closest_p.x = p.x; closest_p.y = -l.c;
      return true;
    }
    else
      return false;
  }
  line perp; // perpendicular to l through p
  point_and_slope_to_line(p, 1.0 / l.a, perp); // non-degenerate line
  intersection_point(l, perp, closest_p);
  return point_in_box(closest_p, sp1, sp2);
}

void generate_compass_points(map<string, double>& compass_points)
{
  const pair<string, double> cps[] = {
    make_pair("N", 0.5 * pi), make_pair("NbE", 0.4375 * pi),
    make_pair("NNE", 0.375 * pi), make_pair("NEbN", 0.3125 * pi),
    make_pair("NE", 0.25 * pi), make_pair("NEbE", 0.1875 * pi),
    make_pair("ENE", 0.125 * pi), make_pair("EbN", 0.0625 * pi),
    make_pair("E", 0.0), make_pair("EbS", -0.0625 * pi),
    make_pair("ESE", -0.125 * pi), make_pair("SEbE", -0.1875 * pi),
    make_pair("SE", -0.25 * pi), make_pair("SEbS", -0.3125 * pi),
    make_pair("SSE", -0.375 * pi), make_pair("SbE", -0.4375 * pi),
    make_pair("S", -0.5 * pi), make_pair("SbW", -0.5625 * pi),
    make_pair("SSW", -0.625 * pi), make_pair("SWbS", -0.6875 * pi),
    make_pair("SW", -0.75 * pi), make_pair("SWbW", -0.8125 * pi),
    make_pair("WSW", -0.875 * pi), make_pair("WbS", -0.9375 * pi),
    make_pair("W", pi), make_pair("WbN", 0.9375 * pi),
    make_pair("WNW", 0.875 * pi), make_pair("NWbW", 0.8125 * pi),
    make_pair("NW", 0.75 * pi), make_pair("NWbN", 0.6875 * pi),
    make_pair("NNW", 0.625 * pi), make_pair("NbW", 0.5625 * pi)
  };
  for (size_t i = 0, n = sizeof(cps) / sizeof(pair<string, double>); i < n; i++)
    compass_points.insert(cps[i]);
}

void convert_to_point(double angle, int distance, point& p)
{
  p.x += cos(angle) * distance;
  p.y += sin(angle) * distance;
}

void convert_to_point(double angle, int distance, const point& previous,
  point& current)
{
  current.x = previous.x + cos(angle) * distance;
  current.y = previous.y + sin(angle) * distance;
}

int main(int /* argc */, char** /* argv */)
{
  map<string, double> compass_points;
  generate_compass_points(compass_points);
  while (true) {
    int nr_steps; // number of steps
    cin >> nr_steps;
    if (!nr_steps)
      break;
    vector<double> angles(nr_steps + 1);
    vector<int> paces(nr_steps + 1);
    angles[0] = 0.0; paces[0] = 0;
    point x; // point marked X where the treasure is located
    for (int i = 0; i < nr_steps; i++) {
      string cp; // compass point
      cin >> cp >> paces[i + 1];
      // get an angle (between -pi and pi) for the compass_point, and then
      // get the point coordinates from the angle, and the paces
      convert_to_point(angles[i + 1] = compass_points[cp], paces[i + 1], x);
    }
    double degree; // degree from north
    cin >> degree;
    double angle = degree * pi / 180.0; // convert to the angle in radian
    vector<point> points(nr_steps + 1);
    points[0].x = points[0].y = 0.0; // the first point is the original point
    for (int i = 0; i < nr_steps; i++) // rotate points by the angle
      convert_to_point(angles[i + 1] + angle, paces[i + 1], points[i],
        points[i + 1]);
    double least_distance = euclidean_distance(points[0], x);
    for (int i = 0; i < nr_steps; i++) {
      // get the closest point on the line segment from x
      point closest_p;
      double distance = (closest_point_from_line_segment(x,
          points[i], points[i + 1], closest_p)) ?
        euclidean_distance(closest_p, x) :
        min(euclidean_distance(points[i], x),
          euclidean_distance(points[i + 1], x));
      least_distance = min(least_distance, distance);
    }
    printf("%.2f\n", least_distance);
  }
  return 0;
}