Sunday, January 27, 2013

UVa 10160 - Servicing Stations

Accepted date: 2011-02-28
Ranking (as of 2013-01-27): 288
Language: C++

Backtrack with pruning.

/*
  8.6.4 Servicing Stations
  PC/UVa IDs: 110804/10160, Popularity: B, Success rate: low Level: 3

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

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

void dominating_set(const vector<int>& vertices,
  int n /* number of vertices */, int iv /* index to the vector of vertices */,
  int v /* number of vertices used so far */,
  const vector<unsigned long long>& adjacency,
  const vector<unsigned long long>& coverable,
  const unsigned long long all_covered, unsigned long long covered,
  int& min_covered)
{
  if (min_covered <= v + 1 || iv == n)
    return; // no need to further search
  if ((covered | coverable[iv]) != all_covered)
    return;
  int i = vertices[iv];
  unsigned long long current = static_cast<unsigned long long>(1) << i;
  unsigned long long c = covered | adjacency[i] | current;
  if (c == all_covered) {
#ifdef DEBUG
    cout << "min. number of vertices = " << v + 1 << endl;
#endif
    min_covered = v + 1;
    return;
  }
  dominating_set(vertices, n, iv + 1, v + 1,
    adjacency, coverable, all_covered, c, min_covered);
  dominating_set(vertices, n, iv + 1, v, 
    adjacency, coverable, all_covered, covered, min_covered);
}

int main(int /* argc */, char** /* argv */)
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  int n, m;
  while (cin >> n >> m) {
    if (!n && !m)
      break;
    vector<unsigned long long> adjacency(n, 0);
      // adjacency bitmap of n vertices
    for (int i = 0; i < m; i++) {
      int u, v;
      cin >> u >> v;
      u--; v--;
      adjacency[u] |= static_cast<unsigned long long>(1) << v;
      adjacency[v] |= static_cast<unsigned long long>(1) << u;
    }
    multimap<int, int, greater<int> > degrees;
      // value is a vertex, key is its degree
    for (int i = 0; i < n; i++) {
      int degree = 0;
      for (int j = 0; j < n; j++)
        if (adjacency[i] & (static_cast<unsigned long long>(1) << j))
          degree++;
      degrees.insert(pair<int, int>(degree, i));
    }
    vector<int> vertices(n);
      // vector of vertices in descending order of their degrees
    vector<int>::iterator i = vertices.begin();
    for (multimap<int, int, greater<int> >::const_iterator 
      j = degrees.begin(); j != degrees.end(); j++) {
#ifdef DEBUG
      cout << j->first << ' ' << j->second << endl;
#endif
      *i++ = j->second;
    }
#ifdef DEBUG
    cout << endl;
#endif
    vector<unsigned long long> coverable(n);
      // coverable[i] is the bitmap covered by the set of vertices from 
      // vertices[i] - vertices[n - 1]
    unsigned long long c = 0;
    for (int iv = n - 1; iv >= 0; iv--) {
      int i = vertices[iv];
      c |= adjacency[i] | (static_cast<unsigned long long>(1) << i);
      coverable[iv] = c;
    }
    unsigned long long all_covered =
      (static_cast<unsigned long long>(1) << n) - 1, covered = 0;
    int min_covered = n;
    dominating_set(vertices, n, 0, 0,
      adjacency, coverable, all_covered, covered, min_covered);
    cout << min_covered << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10135 - Herding Frosh

Accepted date: 2011-06-04
Ranking (as of 2013-01-27): 47
Language: C++

Used the two variations of Graham's scan algorithm.
Although this solution was accepted, the below convex_hull function is a bit doubtful and still may include some other bugs.

/*
  14.7.1 Herding Frosh
  PC/UVa IDs: 111401/10135, Popularity: C, Success rate: average Level: 2

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

#include <iostream>
#include <vector>
#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 x == p.x && y == p.y;}
};

#ifdef DEBUG
ostream& operator<<(ostream& os, const point& p)
{
  os << '(' << p.x << ", " << p.y << ')';
  return os;
}
#endif

bool left_lower(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;
}

void sort_and_remove_duplicates(vector<point>& points,
  bool (*compare)(const point&, const point&) /* = left_lower */)
{
  sort(points.begin(), points.end(), compare);
    // 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++;
  }
}

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 collinear(const point& a, const point& b, const point& c)
{
  return fabs(signed_triangle_area(a, b, c)) <= EPSILON;
}

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

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

bool cw(const point& a, const point& b, const point& c)
{
  // see if the point c is to the right of a -> b 
  // (or, a - b - c are clockwise)
  return signed_triangle_area(a, b, c) < -EPSILON;
}

struct smaller_angle {
  const point& first;

  smaller_angle(const point& _first) : first(_first) {}
  bool operator() (const point& p1, const point& p2) const;
};

bool smaller_angle::operator() (const point& p1, const point& p2) const
{
  if (collinear(first, p1, p2))
    return euclidean_distance(first, p1) <= euclidean_distance(first, p2);
  else
    return ccw(first, p1, p2);
}

int convex_hull(vector<point>& points, vector<point>& hull)
{
  sort_and_remove_duplicates(points, left_lower);
    // sort the points in leftmost-lowest order
  vector<point>::iterator i = points.begin();
  i++;
  sort(i, points.end(), smaller_angle(points[0]));
    // sort the second and later points in increasing angular order
  hull.resize(points.size());
  hull[0] = points[0]; hull[1] = points[1];
  int j = 1;
  for (int i = 2; i < points.size(); ) {
    if (cw(hull[j - 1], hull[j], points[i]))
      j--; // remove hulll[j]
    else {
      if (!collinear(hull[j - 1], hull[j], points[i]))
        j++;
      hull[j] = points[i++];
    }
  }
  if (cw(hull[j - 1], hull[j], points[0]))
    ;
  else
    j++;
  hull.resize(j);
  return hull.size();
}

#ifdef DEBUG
void print_polygon(const vector<point>& points)
{
  for (vector<point>::const_iterator i = points.begin();
    i != points.end(); i++)
    cout << *i << endl;
}
#endif

struct smaller_polar_angle {
  point p;
  double angle;

  smaller_polar_angle(const point& _p) : p(_p), angle(atan2(p.y, p.x)) {}
  bool operator() (const point& p1, const point& p2) const;
};

bool smaller_polar_angle::operator() (const point& p1, const point& p2) const
{
  double a1 = atan2(p1.y, p1.x) - angle, a2 = atan2(p2.y, p2.x) - angle;

  if (fabs(a1 - a2) <= EPSILON)
    return euclidean_distance(p, p1) < euclidean_distance(p, p2);

  if (a1 < 0)
    a1 += pi * 2.0;
  if (a2 < 0)
    a2 += pi * 2.0;
  return a1 < a2;
}

int convex_hull_ex(vector<point>& points, vector<point>& hull)
{
  point original_point;
  hull.resize(points.size());
  hull[0] = points[0]; hull[1] = points[1];
  int j = 1;
  for (int i = 2; i < points.size(); ) {
    if (!j)
      hull[++j] = points[i++];
    else if (cw(hull[j - 1], hull[j], points[i])) {
      if (hull[j] == original_point)
        hull[++j] = points[i++];
      else
        j--; // remove hulll[j]
    }
    else {
/*
      if (hull[j] == original_point ||
        !collinear(hull[j - 1], hull[j], points[i]))
*/
        j++;
      hull[j] = points[i++];
    }
  }
  for ( ; j; j--) {
    if (hull[j] == original_point)
      break;
    else if (cw(hull[j - 1], hull[j], points[0]))
      ;
    else
      break;
  }
  j++;
  hull.resize(j);
  return hull.size();
}

double polygon_perimeter(const vector<point>& polygon)
{
  double perimeter = 0.0;
  for (int i = 0; i < polygon.size(); i++) {
    int j = (i + 1) % polygon.size();
    perimeter += euclidean_distance(polygon[i], polygon[j]);
  }
  return perimeter;
}

int main(int /* argc */, char** /* argv */)
{
  int nr_cases;
  cin >> nr_cases;
  for (int c = 0; c < nr_cases; c++) {
    int nr_frosh;
    cin >> nr_frosh;
    point original_point;
    vector<point> frosh(nr_frosh + 1);
    frosh[0] = original_point;
    for (int i = 1; i <= nr_frosh; i++)
      cin >> frosh[i].y >> frosh[i].x;

    if (nr_frosh < 2) { // special cases
      double perimeter = (nr_frosh) ?
        2.0 /* one extra meter at each end */ +
        euclidean_distance(frosh[0], frosh[1]) * 2.0 : 2.0;
      printf("%.2f\n", perimeter);
      if (c < nr_cases - 1)
        cout << endl; // print a blank line between the two consecutive cases
      continue;
    }

    vector<point> hull;
    convex_hull(frosh, hull);
      // if a frosh is at the original point, 
      // the convex_hull function removes the duplicate points.
#ifdef DEBUG
    cout << endl; print_polygon(hull);
#endif
    double min_perimeter = DBL_MAX;
    if (find(hull.begin(), hull.end(), original_point) != hull.end())
      // the original point is one of the vertices of the convex hull
      min_perimeter = polygon_perimeter(hull);
    else {
      frosh.erase(find(frosh.begin(), frosh.end(), original_point));
      nr_frosh = frosh.size();
      vector<point>::iterator i = frosh.begin();
      i++;
      // sort the 2nd and and later points by their polar angles, 
      // being the angle of the 1st point as the reference one
      sort(i, frosh.end(), smaller_polar_angle(frosh[0]));
#ifdef DEBUG
      cout << endl; print_polygon(frosh);
#endif
      for (int j = 0; j < nr_frosh; j++) {
        i = frosh.insert(i, original_point);
        // calculate the convex hull 
        // except for the original point and its neigbors
        convex_hull_ex(frosh, hull);
        double perimeter = polygon_perimeter(hull);
#ifdef DEBUG
        cout << endl; print_polygon(hull);
        cout << perimeter << endl;
#endif
        min_perimeter = min(min_perimeter, perimeter);
        i = frosh.erase(i);
        if (i != frosh.end())
          i++;
      }
    }
    printf("%.2f\n", 2.0 /* one extra meter at each end */ + min_perimeter);
    if (c < nr_cases - 1)
      cout << endl; // print a blank line between the two consecutive cases
  }
  return 0;
}

UVa 275 - Expanding Fractions

Accepted date: 2012-09-30
Ranking (as of 2013-01-27): 628
Language: C++

/*
  UVa 275 - Expanding Fractions

  To build using Visual Studio 2008:
    cl -EHsc -O2 expanding_fractions.cpp

  This problem is similar to 202 - Repeating Decimals.
*/

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

int main()
{
  while (true) {
    int numerator, denominator;
    cin >> numerator >> denominator;
    if (!numerator && !denominator)
      break;
    int quotient = numerator / denominator;
    numerator -= quotient * denominator;
    map<int, size_t> remainders;
    vector<int> quotients;
    remainders.insert(make_pair(numerator, quotients.size()));
    size_t repeat;
    while (true) {
      if (numerator < denominator)
        numerator *= 10;
      quotient = numerator / denominator;
      quotients.push_back(quotient);
      numerator -= quotient * denominator;
      pair<map<int, size_t>::iterator, bool> result =
        remainders.insert(make_pair(numerator, quotients.size()));
      if (!result.second) {
        repeat = result.first->second;
        break;
      }
    }
    size_t nr_repeat = quotients.size() - repeat;
    if (!numerator) {
      quotients.pop_back();
      nr_repeat = 0;
    }
    const size_t max_nr_print = 50;
    cout << '.';
    int nr_printed = 1;
    size_t i = 0, j = quotients.size();
    for ( ; i < j; i++) {
      cout << quotients[i];
      if (++nr_printed == max_nr_print) {
        cout << endl;
        nr_printed = 0;
      }
    }
    if (nr_printed)
      cout << endl;
    if (nr_repeat)
      cout << "The last " << j - repeat <<
        " digits repeat forever.\n\n";
    else
      cout << "This expansion terminates.\n\n";
  }
  return 0;
}

UVa 10299 - Relatives

Accepted date: 2012-10-07
Ranking (as of 2013-01-27): 628
Language: C++

/*
  UVa 10299 - Relatives

  To build using Visual Studio 2008:
    cl -EHsc -O2 relatives.cpp

  This problem is similar to 10179 - Irreducable Basic Fractions.
*/

/*
  Utilize Euler's totient or phi function, φ(n).
  φ(n) is an arithmetic function 
  that counts the number of positive integers less than or equal to n 
  that are relatively prime to n.
*/

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

int phi_function(int n)
{
  int phi = n;
  bool a_new_prime = true;
  for ( ; !(n & 1); n >>= 1)
    if (a_new_prime) {
      a_new_prime = false;
      phi >>= 1; // phi /= 2
    }
  a_new_prime = true;
  for (int i = 3, e = static_cast<int>(sqrt(static_cast<double>(n) + 1.0));
    i <= e; ) {
    if (!(n % i)) {
      if (a_new_prime) {
        a_new_prime = false;
        phi /= i; phi *= i - 1;
      }
      n /= i;
    }
    else {
      i += 2;
      a_new_prime = true;
    }
  }
  if (n > 1) {
    phi /= n; phi *= n - 1;
  }
  return phi;
}

int main()
{
  while (true) {
    int n;
    cin >> n;
    if (!n)
      break;
    cout << ((n == 1) ? 0 : phi_function(n)) << endl;
  }
  return 0;
}

UVa 727 - Equation

Accepted date: 2012-10-07
Ranking (as of 2013-01-27): 82
Language: C++

/*
  UVa 727 - Equation

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

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

int get_operator_priority(char c)
{
  int p = 0;
  switch (c) {
  case '*': case '/':
    return 2;
  case '+': case '-':
    return 1;
  default:
    return 0;
  }
}

void infix2postfix(const char* i)
{
  char c, d;
  stack<char> st;
  for ( ; *i; i++) {
    c = *i;
    if (c >= '0' && c <= '9')
      putchar(c);
    else if (c == '(')
      st.push(c);
    else if (c == ')') {
      d = st.top();
      st.pop();
      while (d != '(') {
        putchar(d);
        d = st.top();
        st.pop();
      }
    }
    else { // operators
      if (st.empty())
        st.push(c);
      else {
        while (!st.empty() &&
          get_operator_priority(st.top()) >= get_operator_priority(c)) {
          putchar(st.top());
          st.pop();
        }
        st.push(c);
      }
    }
  }
  while (!st.empty()) {
    putchar(st.top());
    st.pop();
  }
  putchar('\n');
}

int main()
{
  int t;
  scanf("%d", &t);
  getchar();
  getchar();
  while (t--) {
    const int nr_chars_max = 50;
    char c, s[nr_chars_max + 1];
    char* ps = s;
    while ((c = getchar()) != EOF && c != '\n') {
      *ps++ = c;
      getchar();
    }
    *ps = '\0';
    infix2postfix(s);
    if (t)
      putchar('\n');
  }
  return 0;
}

UVa 555 - Bridge Hands

Accepted date: 2012-10-11
Ranking (as of 2013-01-27): 299
Language: C++

/*
  UVa 555 - Bridge Hands

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

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

const int nr_cards = 52, nr_players = 4;

struct card {
  char suit_;
  char rank_;

  bool operator<(const card& c) const;
} cards[nr_players][nr_cards / nr_players];
  // cards[0] are for N, cards[1] are for E, 
  // cards[2] are for S, cards[3] are for W

int nr_cards_delivered[nr_players]; // number of cards delivered so far 

int get_suit(char suit)
{
  switch (suit) {
  case 'C':
    return 0;
  case 'D':
    return 1;
  case 'S':
    return 2;
  default:
    return 3;
  }
}

int get_rank(char rank)
{
  switch (rank) {
  case 'T':
    return 8;
  case 'J':
    return 9;
  case 'Q':
    return 10;
  case 'K':
    return 11;
  case 'A':
    return 12;
  default:
    return rank - '2';
  }
}

bool card::operator<(const card& c) const
{
  int s = get_suit(suit_), cs = get_suit(c.suit_);
  if (s < cs)
    return true;
  else if (s > cs)
    return false;
  else
    return get_rank(rank_) < get_rank(c.rank_);
}

void print_cards(card cards[])
{
  for (int i = 0; i < nr_cards / nr_players; i++)
    cout << ' ' << cards[i].suit_ << cards[i].rank_;
  cout << endl;
}

int main()
{
  while (true) {
    char p;
    cin >> p;
    if (p == '#')
      break;
    int pi;
    switch (p) {
    case 'N':
      pi = 1; break;
    case 'E':
      pi = 2; break;
    case 'S':
      pi = 3; break;
    case 'W':
      pi = 0; break;
    }
    for (int i = 0; i < nr_players; i++)
      nr_cards_delivered[i] = 0;
    for (int i = 0; i < nr_cards; i++, pi = (pi + 1) % nr_players) {
      cin >> cards[pi][nr_cards_delivered[pi]].suit_ >>
        cards[pi][nr_cards_delivered[pi]].rank_;
      nr_cards_delivered[pi]++;
    }
    for (int i = 0; i < nr_players; i++)
      sort(cards[i], cards[i] + nr_cards / nr_players);
    cout << "S:";
    print_cards(cards[2]);
    cout << "W:";
    print_cards(cards[3]);
    cout << "N:";
    print_cards(cards[0]);
    cout << "E:";
    print_cards(cards[1]);
  }
  return 0;
}

UVa 10036 - Divisibility

Accepted date: 2012-10-13
Ranking (as of 2013-01-27): 182
Language: C++

/*
  UVa 10036 - Divisibility

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

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

const int n_max = 10000, k_max = 100;
int integers[n_max];
bool remainders[2][k_max];
  // remainders[][i] is true if (sum of the integers) % k == i

bool calculate_remainders(int n, int k)
{
  for (int i = 0; i < k; i++)
    remainders[0][i] = false;
  remainders[0][integers[0] % k] = true;
  for (int i = 1; i < n; i++) {
    int pri = (i - 1) % 2, cri = i % 2;
    for (int j = 0; j < k; j++) {
      int r = integers[i] % k;
      remainders[cri][j] = remainders[pri][(j - r + k) % k] ||
        remainders[pri][(j + r) % k];
    }
  }
  return remainders[(n - 1) % 2][0];
}

int main()
{
  int m;
  cin >> m;
  while (m--) {
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
      int j;
      cin >> j;
      integers[i] = abs(j);
    }
    cout << ((calculate_remainders(n, k)) ? "Divisible\n" : "Not divisible\n");
  }
  return 0;
}

UVa 10080 - Gopher II

Accepted date: 2012-10-15
Ranking (as of 2013-01-27): 486
Language: C++

/*
  UVa 10080 - Gopher II

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

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

const int nr_gophers_max = 100, nr_holes_max = 100;

pair<double, double> gophers[nr_gophers_max], holes[nr_holes_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);
}

struct edge {
  int v; // neighboring vertex
  int capacity; // capacity of edge
  int flow; // flow through edge
  int residual; // residual capacity of edge

  edge(int _v, int _capacity, int _residual) : v(_v), capacity(_capacity),
    flow(0), residual(_residual) {}
};

struct vertex_state {
  bool discovered;
  int parent;

  vertex_state() : discovered(false), parent(-1) {}
};

void bfs(const vector< vector<edge> >& graph,
  int start, vector<vertex_state>& states)
{
  queue<int> q;
  states[start].discovered = true;
  q.push(start);
  while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int i = 0; i < graph[u].size(); i++) {
      const edge& e = graph[u][i];
      if (e.residual > 0 && !states[e.v].discovered) {
        states[e.v].discovered = true;
        states[e.v].parent = u;
        q.push(e.v);
      }
    }
  }
}

edge& find_edge(vector< vector<edge> >& graph, int u, int v)
{
  int i;
  for (i = 0; i < graph[u].size(); i++)
    if (graph[u][i].v == v)
      break;
  return graph[u][i];
}

int path_volume(vector< vector<edge> >& graph,
  int start, int end, const vector<vertex_state>& states)
{
  if (states[end].parent == -1)
    return 0;
  edge& e = find_edge(graph, states[end].parent, end);
  if (start == states[end].parent)
    return e.residual;
  else
    return min(path_volume(graph, start, states[end].parent, states),
      e.residual);
}

void augment_path(vector< vector<edge> >& graph,
  int start, int end, const vector<vertex_state>& states, int volume)
{
  if (start == end)
    return;
  edge& e = find_edge(graph, states[end].parent, end);
  if (e.flow < e.capacity)
    e.flow += volume;
  if (e.residual)
    e.residual -= volume;
  edge& r= find_edge(graph, end, states[end].parent);
  if (r.flow)
    r.flow -= volume;
  if (r.residual < r.capacity)
    r.residual += volume;
  augment_path(graph, start, states[end].parent, states, volume);
}

void netflow(vector< vector<edge> >& graph, int source, int sink)
{
  while (true) {
    vector<vertex_state> states(graph.size());
    bfs(graph, source, states);
    int volume = path_volume(graph, source, sink, states);
      // calculate the volume of augmenting path
    if (volume > 0)
      augment_path(graph, source, sink, states, volume);
    else
      break;
  }
}

int total_flow(const vector< vector<edge> >& graph, int source)
{
  int flow = 0;
  const vector<edge>& edges = graph[source];
  for (int i = 0, e = edges.size(); i < e; i++)
    flow += edges[i].flow;
  return flow;
}

int main()
{
  int nr_gophers, nr_holes;
  double seconds, velocity;
  while (cin >> nr_gophers >> nr_holes >>
    seconds >> velocity) {
    for (int i = 0; i < nr_gophers; i++)
      cin >> gophers[i].first >> gophers[i].second;
    for (int i = 0; i < nr_holes; i++)
      cin >> holes[i].first >> holes[i].second;
    int nr_vertices = nr_gophers + nr_holes + 2;
    vector< vector<edge> > graph(nr_vertices);
    // indices are:
    //  0 - (nr_gophers - 1): gopher vertices,
    //  nr_gophers - (nr_gophers + nr_holes - 1): hole vertices,
    //  (nr_gophers + nr_holes): source vertex,
    // (nr_gophers + nr_holes + 1): sink vertex
    int source = nr_gophers + nr_holes, sink = nr_gophers + nr_holes + 1;
    double d = velocity * seconds;
    for (int i = 0; i < nr_gophers; i++) {
      // append the edges between the source and gopher vertices
      graph[source].push_back(edge(i, 1, 1));
      graph[i].push_back(edge(source, 1, 0));
      for (int j = 0; j < nr_holes; j++)
        if (euclidean_distance(gophers[i], holes[j]) <= d) {
          // append the edges between gopher vertices and hole vertices
          // if a gopher can reach the hole in the specified time
          graph[i].push_back(edge(nr_gophers + j, 1, 1));
          graph[nr_gophers + j].push_back(edge(i, 1, 0));
        }
    }
    for (int i = nr_gophers; i < nr_gophers + nr_holes; i++) {
      // append the edges between hole vertices and the sink
      graph[i].push_back(edge(sink, 1, 1));
      graph[sink].push_back(edge(i, 1, 0));
    }
    netflow(graph, source, sink);
      // apply Ford-Fulkerson's augmenting path algorithm
    cout << nr_gophers - total_flow(graph, source) << endl;
  }
  return 0;
}

Tuesday, January 22, 2013

UVa 164 - String Computer

Accepted date: 2012-10-23
Ranking (as of 2013-01-22): 224
Language: C++

/*
  UVa 164 - String Computer

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

#include <cstdio>
#include <cstring>

const int nr_chars_max = 20;

enum {editMatchOrReplace, editInsert, editDelete};

struct edit_state {
  int cost_; // cost of reaching this state
    int parent_; // parent state
} edite_states[nr_chars_max + 1][nr_chars_max + 1];

int edit_distance(const char* s, const char* t, int sl, int tl)
{
  for (int i = 0; i < nr_chars_max + 1; i++) {
    // first row
    edite_states[0][i].cost_ = i;
    edite_states[0][i].parent_ =  (i) ? editInsert : -1;
    // first column
        edite_states[i][0].cost_ = i;
    edite_states[i][0].parent_ = (i) ? editDelete : -1;
  }

  for (int i = 1; i < sl; i++)
    for (int j = 1; j < tl; j++) {
      int costs[editDelete - editMatchOrReplace + 1];
      // For inserting or deleting or replacing characters, cost is one, 
      // while for maching characters, cost is zero.
      costs[editMatchOrReplace] = edite_states[i - 1][j - 1].cost_ +
        ((s[i] == t[j]) ? 0 : 1);
      costs[editInsert] = edite_states[i][j - 1].cost_ + 1;
      costs[editDelete] = edite_states[i - 1][j].cost_ + 1;
      edite_states[i][j].cost_ = costs[editMatchOrReplace];
      edite_states[i][j].parent_ = editMatchOrReplace;
      for (int k = editInsert; k <= editDelete; k++)
        if (costs[k] < edite_states[i][j].cost_) {
          edite_states[i][j].cost_ = costs[k];
          edite_states[i][j].parent_ = k;
        }
    }
  return edite_states[sl - 1][tl - 1].cost_;
} 

void reconstruct_path(char* s, char* t, int i, int j, int& p)
{
  int parent = edite_states[i][j].parent_;
  if (parent == -1)
    p = 1;
  else if (parent == editMatchOrReplace) {
    reconstruct_path(s, t, i - 1,j - 1, p);
    if (s[i] != t[j])
      printf("C%c%02d", t[j], p);
    p++;
  }
  else if (parent == editInsert) {
    reconstruct_path(s, t, i, j - 1, p);
    printf("I%c%02d", t[j], p);
    p++;
  }
  else if (parent == editDelete) {
    reconstruct_path(s, t, i - 1, j, p);
    printf("D%c%02d", s[i], p);
  }
}

int main()
{
  while (true) {
    char s[nr_chars_max + 2], t[nr_chars_max + 2];
    s[0] = t[0] = ' ';
    scanf("%s", &s[1]);
    if (s[1] == '#')
      break;
    scanf("%s", &t[1]);
    int sl = strlen(s), tl = strlen(t);
    edit_distance(s, t, sl, tl);
    int p;
    reconstruct_path(s, t, sl - 1, tl - 1, p);
    printf("E\n");
  }
  return 0;
}

UVa 201 - Squares

Accepted date: 2012-10-25
Ranking (as of 2013-01-22): 303
Language: C++

/*
  UVa 201 - Squares

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

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

const int n_max = 9;
bool connections[n_max * n_max][n_max * n_max];
  // connections[i][j] is true if a line between row = i / n, column = i % n and 
  // row = j / n, column = j % n
int horizontal_lines[n_max][n_max];
  // horizontal_lines[i][j] is the horizontal line length starting from 
  // row = i, column = j
int vertical_lines[n_max][n_max];
  // vertical_lines[i][j] is the vertical line length starting from 
  // row = i, column = j

int main()
{
  int pn = 0;
  int n, m;
  while (cin >> n >> m) {
    if (pn)
      cout << "\n**********************************\n\n";
    for (int i = 0; i < n * n; i++)
      for (int j = 0; j < n * n; j++)
        connections[i][j] = false;
    while (m--) {
      char d;
      int i, j;
      cin >> d >> i >> j;
      i--; j--;
      if (i < 0 || i >= n || j < 0 || j >= n)
        continue;
      if (d == 'H')
        connections[i * n + j][i * n + j + 1] = true;
      else
        connections[j * n + i][(j + 1) * n + i] = true;
    }
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n - 1; j++) {
        horizontal_lines[i][j] = 0;
        for (int k = j; k < n - 1; k++) {
          if (connections[i * n + k][i * n + k + 1])
            horizontal_lines[i][j]++;
          else
            break;
        }
      }
    for (int j = 0; j < n; j++)
      for (int i = 0; i < n - 1; i++) {
        vertical_lines[i][j] = 0;
        for (int k = i; k < n - 1; k++) {
          if (connections[k * n + j][(k + 1) * n + j])
            vertical_lines[i][j]++;
          else
            break;
        }
      }
    cout << "Problem #" << pn + 1 << endl << endl;
    int nr_total_squares = 0;
    for (int s = 1; s < n; s++) {
      int nr_squares = 0;
      for (int i = 0; i < n - s; i++)
        for (int j = 0; j < n - s; j++)
          if (horizontal_lines[i][j] >= s && horizontal_lines[i + s][j] >= s &&
            vertical_lines[i][j] >= s && vertical_lines[i][j + s] >= s)
            nr_squares++;
      if (nr_squares) {
        nr_total_squares += nr_squares;
        cout << nr_squares << " square (s) of size " << s << endl;
      }
    }
    if (!nr_total_squares)
      cout << "No completed squares can be found.\n";
    pn++;
  }
  return 0;
}

Sunday, January 20, 2013

UVa 10415 - Eb Alto Saxophone Player

Accepted date: 2013-01-20
Ranking (as of 2013-01-20): 42
Language: C++

/*
  UVa 10415 - Eb Alto Saxophone Player

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

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

const int nr_fingers = 10, nr_notes_max = 200;

int notes[] = {0x006, 0x002, 0x3ce, 0x1ce, 0x0ce, 0x04e, 0x00e};
  // notes[i] is the finger pattern for i - 'a'
int high_notes[] = {0x007, 0x003, 0x004, 0x1cf, 0x0cf, 0x004f, 0x00f};
  // high_notes[i] is the finger pattern for i - 'A'

int main()
{
  int t;
  scanf("%d", &t);
  getchar();
  while (t--) {
    int nr_presses[nr_fingers];
    memset(nr_presses, 0, sizeof(nr_presses));
    char s[nr_notes_max + 1];
    gets(s);
    int finger_pattern = 0;
    for (const char* p = s; *p; p++)
      if (isalpha(*p)) {
        int note = (isupper(*p)) ? high_notes[*p - 'A'] : notes[*p - 'a'];
        int d = finger_pattern ^ note;
        int f = d & note;
        for (int i = 0, b = 1; i < nr_fingers; i++, b <<= 1)
          if (f & b)
            nr_presses[i]++;
        finger_pattern = note;
      }
    for (int i = 0; i < nr_fingers; i++)
      printf("%d%c", nr_presses[i], ((i == nr_fingers - 1) ? '\n' : ' '));
  }
  return 0;
}

UVa 10539 - Almost Prime Numbers

Accepted date: 2012-11-01
Ranking (as of 2013-01-20): 43
Language: C++

/*
  UVa 10539 - Almost Prime Numbers

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

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

const long long n_max = 1000000000000;
const int sqrt_n_max = 1000000;
bool not_primes[sqrt_n_max + 1]; // not_primes[i] is true if i is not a prime
const int nr_almost_primes_max = 100000;
long long almost_primes[nr_almost_primes_max];

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

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  sieve_of_eratosthenes();
  int nr_almost_primes = 1;
  for (long long j = 4; j <= n_max; j <<= 1)
    almost_primes[nr_almost_primes++] = j;
  for (int i = 3; i <= sqrt_n_max; i += 2) {
    if (!not_primes[i]) {
      long long j = i;
      for (j *= j; j <= n_max; j *= i)
        almost_primes[nr_almost_primes++] = j;
    }
  }
#ifdef DEBUG
  cout << nr_almost_primes << endl;
#endif
  sort(almost_primes, almost_primes + nr_almost_primes);

  int N;
  cin >> N;
  while (N--) {
    long long low, high;
    cin >> low >> high;
    int li = distance(almost_primes,
      upper_bound(almost_primes, almost_primes + nr_almost_primes, low - 1));
    int hi = distance(almost_primes,
      upper_bound(almost_primes, almost_primes + nr_almost_primes, high));
    cout << hi - li << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 628 - Passwords

Accepted date: 2012-11-08
Ranking (as of 2013-01-20): 24
Language: C++

/*
  UVa 628 - Passwords

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

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

const int nr_words_max = 100, nr_word_chars_max = 256;
const int nr_rule_chars_max = 256;
char words[nr_words_max][nr_word_chars_max];
char password[nr_word_chars_max * nr_rule_chars_max];

void print_password(int ri, int rlength, const char* rule,
  int wi, int wlength, int pi)
{
  if (ri == rlength)
    printf("%s\n", password);
  else if (rule[ri] == '#') {
    strcpy(password + pi, words[wi]);
    print_password(ri + 1, rlength, rule, wi, wlength, pi + wlength);
  }
  else {
    for (int i = 0; i < 10; i++) {
      password[pi] = i + '0';
      password[pi + 1] = '\0';
      print_password(ri + 1, rlength, rule, wi, wlength, pi + 1);
    }
  }
}

int main()
{
  while (true) {
    int nr_words;
    if (scanf("%d\n", &nr_words) == EOF)
      break;
    for (int i = 0; i < nr_words; i++)
      gets(words[i]);
    int nr_rules;
    scanf("%d\n", &nr_rules);
    printf("--\n");
    for (int ri = 0; ri < nr_rules; ri++) {
      char rule[nr_rule_chars_max];
      gets(rule);
      int rlength = strlen(rule);
      for (int wi = 0; wi < nr_words; wi++) {
        int wlength = strlen(words[wi]);
        print_password(0, rlength, rule, wi, wlength, 0);
      }
    }
  }
  return 0;
}

UVa 10427 - Naughty Sleepy Boys

Accepted date: 2012-11-11
Ranking (as of 2013-01-20): 601
Language: C++

/*
  UVa 10427 - Naughty Sleepy Boys

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

/*
nr_digits[i]    number of digits  value
-----------------------------------------------
9               1                 1 -        9
189             2                10 -       99
2889            3               100 -      999
38889           4              1000 -     9999
488889          5             10000 -    99999
5888889         6            100000 -   999999
68888889        7           1000000 -  9999999
788888889       8          10000000 - 99999999

N = 10000

10000 - 2889 = 7111
(7111 + 3) / 4 = 1778
(1000 - 1) + 1778 = 2777
7111 % 4 = 3    -> 3rd digit of 2777 --> 7

N = 50000

50000 - 38889 = 11111
(11111 + 4) / 5 = 2223
(10000 - 1) + 2223 = 12222
11111 % 5 = 1   -> 1st digit of 12222 --> 1
*/

#include <iostream>
using namespace std;

int main()
{
  const int i_max = 10;
  int power_of_10[i_max + 1];
  long long nr_digits[i_max + 1];
  nr_digits[0] = 0;
  for (int i = 1, p = 1; i <= i_max; i++, p *= 10) {
    power_of_10[i] = p;
    nr_digits[i] = nr_digits[i - 1] + static_cast<long long>(i) * 9 * p;
#ifdef DEBUG
    cout << power_of_10[i] << ' ' << nr_digits[i] << endl;
#endif
  }
  long long n;
  while (cin >> n) {
    int i = 1;
    while (i <= i_max && n > nr_digits[i])
      i++;
    long long j = n - nr_digits[i - 1];
    long long m = static_cast<long long>(power_of_10[i] - 1) + (j + i - 1) / i;
    if (j % i) {
      for (int k = i - static_cast<int>(j % i); k; k--)
        m /= 10;
    }
    cout << m % 10 << endl;
  }
  return 0;
}

UVa 762 - We Ship Cheap

Accepted date: 2012-11-11
Ranking (as of 2013-01-20): 136
Language: C++

/*
  UVa 762 - We Ship Cheap

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

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

int register_vertex(const string& s, vector<string>& cities,
  map<string, int>& vertices)
{
  pair< map<string, int>::iterator, bool> result =
    vertices.insert(make_pair(s, vertices.size()));
  if (result.second)
    cities.push_back(s);
  return result.first->second;
}

int get_vertex(const string& s, map<string, int>& vertices)
{
  map<string, int>::iterator i = vertices.find(s);
  return (i != vertices.end()) ? i->second : -1;
}

bool bfs(int source, int destination, const vector< vector<int> >& edges,
  vector<int>& parents)
{
  vector<bool> visited(edges.size(), false);
  queue<int> q;
  visited[source] = true;
  q.push(source);
  while (!q.empty()) {
    int i = q.front(); q.pop();
    if (i == destination)
      return true;
    const vector<int>& e = edges[i];
    for (int j = 0; j < e.size(); j++) {
      int k = e[j];
      if (!visited[k]) {
        visited[k] = true;
        parents[k] = i;
        q.push(k);
      }
    }
  }
  return false;
}

void print_routes(int i, const vector<int>& parents,
  const vector<string>& cities)
{
  int p = parents[i];
  if (p != -1) {
    print_routes(p, parents, cities);
    cout << cities[p] << ' ' << cities[i] << endl;
  }
}

int main()
{
  int nr_links;
  bool printed = false;
  while (cin >> nr_links) {
    string s, t;
    vector<string> cities;
    map<string, int> vertices;
    vector< vector<int> > edges;
    while (nr_links--) {
      cin >> s >> t;
      int i = register_vertex(s, cities, vertices),
        j = register_vertex(t, cities, vertices);
      while (i >= edges.size() || j >= edges.size())
        edges.push_back(vector<int>());
      edges[i].push_back(j);
      edges[j].push_back(i);
    }
    cin >> s >> t;
    if (printed)
      cout << endl;
    else
      printed = true;
    int i = get_vertex(s, vertices), j = get_vertex(t, vertices);
    bool result = false;
    if (i != -1 && j != -1) {
      if (i == j) {
        result = true;
        cout << s << ' ' << s << endl;
      }
      else {
        vector<int> parents(edges.size(), -1);
        if (result = bfs(i, j, edges, parents))
          print_routes(j, parents, cities);
      }
    }
    else if (s == t)
      result = true;
    if (!result)
      cout << "No route\n";
  }
  return 0;
}

UVa 115 - Climbing Trees

Accepted date: 2012-11-23
Ranking (as of 2013-01-20): 498
Language: C++

/*
  UVa 115 - Climbing Trees

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

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

const int nr_names_max = 300;
int parents[nr_names_max + 1]; // parents[i] is the index ofi's parent
int iparents; // max. index to parents[]

int register_name(const string& name, map<string, int>& names)
{
  map<string, int>::iterator i = names.find(name);
  if (i != names.end())
    return i->second;
  else {
    names.insert(make_pair(name, ++iparents));
    return iparents;
  }
}

int get_name(const string& name, map<string, int>& names)
{
  map<string, int>::iterator i = names.find(name);
  return (i != names.end()) ? i->second : 0;
}

int is_parent(int pi, int qi) // see if pi is an ancestor of qi
{
  for (int k = 0; parents[qi]; k++, qi = parents[qi])
    if (parents[qi] == pi)
      return k;
  return -1;
}

bool are_cousins(int pi, int qi, int& k, int& j) // see if p and q are cousins
{
  for (int kp = 0; parents[pi]; kp++, pi = parents[pi]) {
    int ri = qi;
    for (int kq = 0 ; parents[ri]; kq++, ri = parents[ri])
      if (parents[pi] == parents[ri]) {
        k = min(kp, kq);
        j = abs(kp - kq);
        return true;
      }
  }
  return false;
}

int main()
{
  string p, q;
  map<string, int> names;
  while (true) {
    cin >> p >> q;
    if (p == "no.child")
      break;
    int pi = register_name(p, names), qi = register_name(q, names);
    parents[pi] = qi;
  }
  while (cin >> p >> q) {
    int k, j;
    int pi = get_name(p, names), qi = get_name(q, names);
    if (!pi || !qi)
      cout << "no relation\n";
    else if ((k = is_parent(pi, qi)) != -1) {
      while (k--)
        cout << ((k) ? "great " : "grand ");
      cout << "parent\n";
    }
    else if ((k = is_parent(qi, pi)) != -1) {
      while (k--)
        cout << ((k) ? "great " : "grand ");
      cout << "child\n";
    }
    else if (parents[pi] && parents[pi] == parents[qi])
      cout << "sibling\n";
    else if (are_cousins(pi, qi, k, j)) {
      cout << k << " cousin";
      if (j)
        cout <<" removed " << j;
      cout << endl;
    }
    else
      cout << "no relation\n";
  }
  return 0;
}

Saturday, January 19, 2013

UVa 384 - Slurpys

Accepted date: 2012-11-26
Ranking (as of 2013-01-19): 1050
Language: C++

/*
  UVa 384 - Slurpys

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

#include <cstdio>
#include <cstring>

int is_slump(const char* s, int i, int length)
{
  int si = i;
  if (i >= length || s[i] != 'D' && s[i] != 'E')
    return -1;
  if (++i == length || s[i] != 'F')
    return -1;
  for (i++; i < length; i++)
    if (s[i] != 'F')
      break;
  if (i == length)
    return -1;
  else if (s[i] == 'G')
    return i - si + 1;
  else {
    int slump_length = is_slump(s, i, length);
    return (slump_length > 0) ? i + slump_length - si : -1;
  }
}

int is_slimp(const char* s, int i, int length)
{
  int si = i;
  if (i >= length || s[i] != 'A')
    return -1;
  if (++i == length)
    return -1;
  else if (s[i] == 'H')
    return 2;
  else if (s[i] == 'B') {
    int slimp_length = is_slimp(s, ++i, length);
    return (slimp_length > 0 && i + slimp_length < length &&
      s[i + slimp_length] == 'C') ? i + slimp_length - si + 1 : -1;
  }
  else {
    int slump_length = is_slump(s, i, length);
    return (slump_length > 0 && i + slump_length < length &&
      s[i + slump_length] == 'C') ? i + slump_length - si + 1 : -1;
  }
}

bool is_slurpys(const char* s)
{
  int length = strlen(s);
  int slimp_length = is_slimp(s, 0, length);
  if (slimp_length > 0) {
    int slump_length = is_slump(s, slimp_length, length);
    return (slimp_length + slump_length == length) ? true : false;
  }
  else
    return false;
}

int main()
{
  int n;
  scanf("%d", &n);
  printf("SLURPYS OUTPUT\n");
  while (n--) {
    const int nr_chars_max = 60;
    char s[nr_chars_max + 1];
    scanf("%s", s);
    printf("%s\n", ((is_slurpys(s)) ? "YES" : "NO"));
  }
  printf("END OF OUTPUT\n");
  return 0;
}

UVa 332 - Rational Numbers from Repeating Fractions

Accepted date: 2012-11-29
Ranking (as of 2013-01-19): 24
Language: C++
/*
  UVa 332 - Rational Numbers from Repeating Fractions

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

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

int gcd(int x, int y)
{
  if (x < y)
    return gcd(y, x);
  else
      return y == 0 ? x : gcd(y, x % y);
}

int main()
{
  const int nr_digits_max = 9;
  const int pow_10s[nr_digits_max + 1] = {
    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
  };
  for (int case_nr = 1; ; case_nr++) {
    int j;
    scanf("%d", &j);
    if (j == -1)
      break;
    char s[nr_digits_max + 3];
    scanf("%s", s);
    int k = strlen(s + 2) - j;
    int n = static_cast<int>(strtol(s + 2, NULL, 10));
    int numerator, denominator;
    if (j) {
      numerator = n - n / pow_10s[j];
      denominator = pow_10s[k + j] - pow_10s[k];
    }
    else {
      numerator = n;
      denominator = pow_10s[k];
    }
    int g = gcd(numerator, denominator);
    printf("Case %d: %d/%d\n", case_nr, numerator / g, denominator / g);
  }
  return 0;
}

UVa 450 - Little Black Book

Accepted date: 2012-12-01
Ranking (as of 2013-01-19): 179
Language: C++

/*
  UVa 450 - Little Black Book

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

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

const int nr_fields = 7;

struct record {
  int idepartment_;
  int ifields_[nr_fields];
  string info_;
};

bool compare_record(const record* i, const record* j)
{
  return strcmp(i->info_.c_str() + i->ifields_[2],
    j->info_.c_str() + j->ifields_[2]) < 0;
}

int main()
{
  int nr_departments;
  cin >> nr_departments;
  string s;
  getline(cin, s);
  vector<string> departments(nr_departments);
  vector<record*> records;
  for (int i = 0; i < nr_departments; i++) {
    getline(cin, departments[i]);
    while (true) {
      record* r = new record();
      if (!getline(cin, r->info_) || r->info_.empty()) {
        delete r;
        break;
      }
      r->idepartment_ = i;
      r->ifields_[0] = 0;
      for (int j = 1, p = 0; j < nr_fields; j++) {
        p = r->info_.find(',', p);
        r->info_[p] = '\0';
        r->ifields_[j] = ++p;
      }
      records.push_back(r);
    }
  }
  sort(records.begin(), records.end(), compare_record);
  for (vector<record*>::const_iterator ri = records.begin(), re = records.end();
    ri != re; ++ri) {
    record* r = *ri;
    const char* info = r->info_.c_str();
    cout << "----------------------------------------\n";
    cout << info + r->ifields_[0] << ' ' <<
      info + r->ifields_[1] << ' ' << info + r->ifields_[2] << endl;
    cout << info + r->ifields_[3] << endl;
    cout << "Department: " << departments[r->idepartment_] << endl;
    cout << "Home Phone: " << info + r->ifields_[4] << endl;
    cout << "Work Phone: " << info + r->ifields_[5] << endl;
    cout << "Campus Box: " << info + r->ifields_[6] << endl;
  }
  return 0;
}

UVa 608 - Counterfeit Dollar

Accepted date: 2012-12-01
Ranking (as of 2013-01-19): 74
Language: C++

/*
  UVa 608 - Counterfeit Dollar

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

#include <cstdio>
#include <cstring>

const int nr_coins_max = 'L' - 'A' + 1, nr_weighings = 3;

struct weighing {
  char left_coins_[nr_coins_max + 1], right_coins_[nr_coins_max + 1];
  int result_; // 1 for "up", 0 for "even", -1 for "down"
};

bool weigh_coins(char coin, int light_or_heavy /* 1 for light, -1 for heavy */,
  weighing& w)
{
  int left_weight = 0, right_weight = 0;
  for (const char* p = w.left_coins_; *p; p++)
    if (*p == coin) {
      left_weight = light_or_heavy;
      break;
    }
  for (const char* p = w.right_coins_; *p; p++)
    if (*p == coin) {
      right_weight = light_or_heavy;
      break;
    }
  return (right_weight == left_weight && !w.result_ ||
    right_weight > left_weight && w.result_ > 0 ||
    right_weight < left_weight && w.result_ < 0) ? true : false;
}

int main()
{
  bool coins[nr_coins_max];
    // coins[i] is true if coin of 'A' + i is used for the weighings
  weighing weighings[nr_weighings];
  int t;
  scanf("%d", &t);
  while (t--) {
    memset(coins, 0, sizeof(coins));
    for (int i = 0; i < nr_weighings; i++) {
      char result[nr_coins_max + 1];
      scanf("%s %s %s",
        weighings[i].left_coins_, weighings[i].right_coins_, result);
      for (const char *p = weighings[i].left_coins_; *p; p++)
        coins[*p - 'A'] = true;
      for (const char *p = weighings[i].right_coins_; *p; p++)
        coins[*p - 'A'] = true;
      weighings[i].result_ = ((!strcmp(result, "even")) ? 0 :
        ((!strcmp(result, "up")) ? 1 : -1));
    }
    for (int i = 0; i < nr_coins_max; i++)
      if (coins[i]) {
        int j;
        // see if the coin of 'A' + i is the heavy counterfeit
        for (j = 0; j < nr_weighings; j++)
          if (!weigh_coins('A' + i, -1, weighings[j]))
            break;
        if (j == nr_weighings) {
          printf("%c is the counterfeit coin and it is heavy.\n", 'A' + i);
          break;
        }
        // see if the coin of 'A' + i is the light counterfeit
        for (j = 0; j < nr_weighings; j++)
          if (!weigh_coins('A' + i, 1, weighings[j]))
            break;
        if (j == nr_weighings) {
          printf("%c is the counterfeit coin and it is light.\n", 'A' + i);
          break;
        }
      }
  }
  return 0;
}

UVa 436 - Arbitrage (II)

Accepted date: 2012-12-05
Ranking (as of 2013-01-19): 156
Language: C++

/*
  UVa 436 - Arbitrage (II)

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

#include <iostream>
#include <string>
#include <map>
#include <limits>
#include <cmath>
using namespace std;

const int n_max = 30;
double matrix[n_max][n_max];

void floyd_warshall(int n)
{
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (matrix[i][k] != numeric_limits<double>::max() &&
          matrix[k][j] != numeric_limits<double>::max()) {
          double through_k = matrix[i][k] + matrix[k][j];
            // distance through vertex k
          if (through_k < matrix[i][j])
            matrix[i][j] = through_k;
        }
}

int main()
{
  for (int case_nr = 1; ; case_nr++) {
    int n;
    cin >> n;
    if (!n)
      break;
     map<string, int> currencies;
    for (int i = 0; i < n; i++) {
      string c;
      cin >> c;
      currencies[c] = i;
    }
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        matrix[i][j] = (i == j) ? 0.0 : numeric_limits<double>::max();
    int m;
    cin >> m;
    for (int i = 0; i < m; i++) {
      string ci, cj;
      double rij;
      cin >> ci >> rij >> cj;
      matrix[currencies[ci]][currencies[cj]] = -log(rij);
    }
    floyd_warshall(n);
    bool yes = false;
    for (int i = 0; i < n; i++) {
      double profit = 1.0 / exp(matrix[i][i]);
      if (profit > 1.0) {
        yes = true; break;
      }
    }
    cout << "Case " << case_nr << ((yes) ? ": Yes\n" : ": No\n");
  }
  return 0;
}

UVa 10147 - Highways

Accepted date: 2012-12-09
Ranking (as of 2013-01-19): 166
Language: C++

/*
  UVa 10147 - Highways

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

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

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

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

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

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

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

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

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

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

  bool operator<(const edge& e) const {return weight_ < e.weight_;}
};

int main()
{
  int t;
  cin >> t;
  while (t--) {
    int n;
    cin >> n;
    vector< pair<int, int> > points(n + 1);
    for (int i = 1; i <= n; i++)
      cin >> points[i].first >> points[i].second;
    union_find vertices(n + 1);
    int m;
    cin >> m;
    for (int i = 0; i < m; i++) {
      int j, k;
      cin >> j >> k;
      vertices.do_union(j, k);
    }
    if (vertices.nr_sets() == 2)
      cout << "No new highways need\n";
    else {
      vector<edge> edges;
      for (int i = 1; i < n; i++)
        for (int j = i + 1; j <= n; j++)
          if (vertices.find(i) != vertices.find(j))
            edges.push_back(edge(i, j,
              euclidean_distance(points[i], points[j])));
      // calculate the minimum spanning tree for the unconnecetd towns
      sort(edges.begin(), edges.end());
      for (vector<edge>::const_iterator ei = edges.begin(), ee = edges.end();
        ei != ee; ++ei)
        if (vertices.do_union(ei->u_, ei->v_) != -1)
#if DEBUG
          cout << ei->u_ << ' ' << ei->v_ <<
            ' ' << ei->weight_ << endl;
#else
          cout << ei->u_ << ' ' << ei->v_ << endl;
#endif
    }
    if (t)
      cout << endl;
  }
  return 0;
}

Wednesday, January 16, 2013

UVa 10803 - Thunder Mountain

Accepted date: 2013-01-15
Ranking (as of 2013-01-16): 126
Language: C++

A straightforward all-pairs shortest path problem.

/*
  UVa 10803 - Thunder Mountain

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

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

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

struct point {
  int x, y;
} points[n_max];

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

void floyd_warshall(int n)
{
  for (int k = 0; k < n; k++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        matrix[i][j] = min(matrix[i][j], matrix[i][k] + matrix[k][j]);
}

int main()
{
  int t;
  cin >> t;
  for (int case_nr = 1; case_nr <= t; case_nr++) {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
      cin >> points[i].x >> points[i].y;
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
         matrix[i][j] = (i == j) ? 0.0 : numeric_limits<float>::max();
    for (int i = 0; i < n - 1; i++)
      for (int j = i + 1; j < n; j++) {
        double d = euclidean_distance(points[i], points[j]);
        if (d <= 10.0)
          matrix[i][j] = matrix[j][i] = d;
      }
    floyd_warshall(n);
    double max_d = 0.0;
    for (int i = 0; i < n - 1; i++)
      for (int j = i + 1; j < n; j++)
        max_d = max(max_d, matrix[i][j]);
    cout << "Case #" << case_nr << ":\n";
    if (max_d == numeric_limits<float>::max())
      cout << "Send Kurdy\n\n";
    else
      cout << fixed << setprecision(4) << max_d << endl << endl;
  }
  return 0;
}

UVa 11362 - Phone List

Accepted date: 2013-01-07
Ranking (as of 2013-01-16): 122
Language: C++

/*
  UVa 11362 - Phone List

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

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

const int n_max = 10000, nr_digits_max = 10;

char phone_numbers[n_max][nr_digits_max + 1];

int compare_phone_number(const void* i, const void* j)
{
  return strcmp(reinterpret_cast<const char*>(i),
    reinterpret_cast<const char*>(j));
}

int main()
{
  int t;
  scanf("%d", &t);
  while (t--) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
      scanf("%s", phone_numbers[i]);
    qsort(phone_numbers, n, nr_digits_max + 1, compare_phone_number);
    bool yes = true;
    for (int i = 0; i < n - 1; i++)
      if (!strncmp(phone_numbers[i], phone_numbers[i + 1],
        strlen(phone_numbers[i]))) {
        yes = false; break;
      }
    printf("%s\n", ((yes) ? "YES" : "NO"));
  }
  return 0;
}

Tuesday, January 15, 2013

UVa 10683 - The decadary watch

Accepted date: 2012-12-11
Ranking (as of 2013-01-15): 127
Language: C++

/*
  UVa 10683 - The decadary watch

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

#include <cstdio>

int main()
{
  const int nr_time_units = 4;
  const int t_time_units[nr_time_units] = {24, 60, 60, 100};
  const int t_time_chars = 8;
  char t_time[t_time_chars + 1];
  while (scanf("%s", t_time) != EOF) {
    long long t = 0;
    for (int i = 0; i < nr_time_units; i++) {
      t *= t_time_units[i];
      t += (t_time[i * 2] - '0') * 10 + (t_time[i * 2 + 1] - '0');
    }
    long long t_time_divisor = 8640000, d_time_divisor = 10000000;
    printf("%07lld\n", (t * d_time_divisor) / t_time_divisor);
  }
  return 0;
}

UVa 227 - Puzzle

Accepted date: 2012-12-13
Ranking (as of 2013-01-15): 123
Language: C++

/*
  UVa 227 - Puzzle

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

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

int main()
{
  const int n = 5;
  char puzzle[n + 1][n + 1];
  for (int case_nr = 1; ; case_nr++) {
    int r, c;
    gets(puzzle[0]);
    if (puzzle[0][0] == 'Z')
      break;
    if (case_nr > 1)
      putchar('\n');
    for (int j = 0; j < n; j++)
      if (puzzle[0][j] == ' ') {
        r = 0; c = j;
      }
    for (int i = 1; i < n; i++) {
      gets(puzzle[i]);
      for (int j = 0; j < n; j++)
        if (puzzle[i][j] == ' ') {
          r = i; c = j;
        }
    }
    bool illegal = false;
    int dc;
    while ((dc = getchar()) != '0') {
      if (illegal)
        continue;
      switch (dc) {
      case 'A':
        if (r) {
          swap(puzzle[r][c], puzzle[r - 1][c]);
          r--;
        }
        else
          illegal = true;
        break;
      case 'B':
        if (r < n - 1) {
          swap(puzzle[r][c], puzzle[r + 1][c]);
          r++;
        }
        else
          illegal = true;
        break;
      case 'L':
        if (c) {
          swap(puzzle[r][c], puzzle[r][c - 1]);
          c--;
        }
        else
          illegal = true;
        break;
      case 'R':
        if (c < n - 1) {
          swap(puzzle[r][c], puzzle[r][c + 1]);
          c++;
        }
        else
          illegal = true;
        break;
      }
    }
    getchar(); // skip '\n'
    printf("Puzzle #%d:\n", case_nr);
    if (illegal)
      printf("This puzzle has no final configuration.\n");
    else {
      for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
          printf("%c%c", puzzle[i][j], (j == n - 1) ? '\n' : ' ');
    }
  }
  return 0;
}

UVa 429 - Word Transformation

Accepted date: 2012-12-18
Ranking (as of 2013-01-15): 45
Language: C++

/*
  UVa 429 - Word Transformation

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

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

const int nr_words_max = 200, nr_chars_max = 10;

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

struct edge {
  int ne_;
  int e_[nr_words_max];
} edges[nr_words_max];

int compare_word(const void* i, const void* j)
{
  return strcmp(reinterpret_cast<const word*>(i)->s_,
    reinterpret_cast<const word*>(j)->s_);
}

bool is_transformable(const word &i, const word& j)
{
  if (i.length_ != j.length_)
    return false;
  else {
    int n = 0;
    for (int k = 0; k < i.length_; k++)
      if (i.s_[k] != j.s_[k])
        if (++n > 1)
          return false;
    return n == 1;
  }
}

bool visited[nr_words_max];

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

int main()
{
  int t;
  scanf("%d", &t);
  getchar();
  getchar(); // skip a blank line
  while (t--) {
    int n = 0;
    while (true) {
      gets(words[n].s_);
      if (words[n].s_[0] == '*')
        break;
      words[n].length_ = strlen(words[n].s_);
      n++;
    }
    qsort(words, n, sizeof(word), compare_word);
    for (int i = 0; i < n; i++)
      edges[i].ne_ = 0;
    for (int i = 0; i < n - 1; i++)
      for (int j = i + 1; j < n; j++)
        if (is_transformable(words[i], words[j])) {
          edges[i].e_[edges[i].ne_++] = j;
          edges[j].e_[edges[j].ne_++] = i;
        }
    char line[2 * (nr_chars_max + 1)];
    while (gets(line) && strlen(line)) {
      word sw, dw;
      sscanf(line, "%s %s", sw.s_, dw.s_);
      int si = reinterpret_cast<word*>(
        bsearch(&sw, words, n, sizeof(word), compare_word)) - words;
      int di = reinterpret_cast<word*>(
        bsearch(&dw, words, n, sizeof(word), compare_word)) - words;
      printf("%s %s %d\n", sw.s_, dw.s_, bfs(n, si, di));
    }
    if (t)
      putchar('\n');
  }
  return 0;
}

UVa 619 - Numerically Speaking

Accepted date: 2012-12-19
Ranking (as of 2013-01-15): 1004
Language: JAVA

/*
  UVa 619 - Numerically Speaking
*/

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

class Main {
  static final BigInteger TWENTY_SIX = BigInteger.valueOf(26);

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    while (true) {
      if (sc.hasNextBigInteger()) {
        BigInteger n = sc.nextBigInteger();
        String s = convertToString(n);
        System.out.printf("%-22s%s%n", s, getNumberToBePrinted(n));
      }
      else if (sc.hasNext()) {
        String s = sc.next();
        if (s.equals("*"))
          break;
        BigInteger n = convertToNumber(s);
        System.out.printf("%-22s%s%n", s, getNumberToBePrinted(n));
      }
    }
  }

  static String convertToString(BigInteger n) {
    StringBuilder sb = new StringBuilder();
    do {
      sb.append((char)('a' +
        n.subtract(BigInteger.ONE).mod(TWENTY_SIX).intValue()));
      n = n.subtract(BigInteger.ONE).divide(TWENTY_SIX);
    } while (n.compareTo(BigInteger.ZERO) != 0);
    sb.reverse();
    return sb.toString();
  }

  static BigInteger convertToNumber(String s) {
    BigInteger n = BigInteger.ZERO;
    for (int i = 0; i < s.length(); i++) {
      n = n.multiply(TWENTY_SIX);
      n = n.add(BigInteger.valueOf((int)(s.charAt(i) - 'a' + 1)));
    }
    return n;
  }

  static String getNumberToBePrinted(BigInteger n) {
    String s = n.toString();
    StringBuilder sb = new StringBuilder();
    for (int i = s.length() - 1, j = 0; i >= 0; i--, j++) {
      sb.append(s.charAt(i));
      if (i > 0 && (j % 3) == 2)
        sb.append(',');
    }
    sb.reverse();
    return sb.toString();
  }
}

Monday, January 14, 2013

UVa 602 - What Day Is It?

Accepted date: 2013-01-12
Ranking (as of 2013-01-14): 191
Language: C++

/*
  UVa 602 - What Day Is It?

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

#include <iostream>
using namespace std;

const char* month_names[] = {
  "January", "February", "March", "April", "May", "June",
  "July", "August","September", "October", "November", "December"
};
const char* weekday_names[] = {"Saturday", "Sunday", "Monday", "Tuesday",
  "Wednesday", "Thursday", "Friday"};
const int month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool is_leap_year(int year)
{
  if (year <= 1752)
    return !(year % 4);
  else {
    if (!(year % 400))
      return true;
    else if (!(year % 100))
      return false;
    else
      return (!(year % 4));
  }
}

bool is_valid_date(int year, int month, int day)
{
  if (year == 1752 && month == 9 && day >= 3 && day <= 13)
    return false;
  if (month > 12)
    return false;
  int d = month_days[month - 1];
  if (month == 2 && is_leap_year(year))
    d++;
  return (day <= d) ? true : false;
}

const char* day_of_week(int year, int month, int day)
{
/*
  Zeller's congruence is used to calculate the day of the week.
*/
  bool gregorian = true;
    // true for Gregorian calender, false for Julian calender
  if (year < 1752)
    gregorian = false;
  else if (year == 1752) {
    if (month < 9)
      gregorian = false;
    else if (month == 9) {
      if (day < 14)
        gregorian = false;
    }
  }
  int q = day;
  if (month < 3) {
    year--; month += 12;
  }
  int m = month, k = year % 100, j = year / 100;
  int h = q + 13 * (m + 1) / 5 + k + k / 4;
  if (gregorian)
    h += j / 4 + 5 * j;
  else
    h += 5 + 6 * j;
  return weekday_names[h % 7];
}

int main()
{
  while (true) {
    int month, day, year;
    cin >> month >> day >> year;
    if (!month && !day && !year)
      break;
    if (is_valid_date(year, month, day))
      cout << month_names[month - 1] << ' ' << day << ", " << year << " is a " <<
        day_of_week(year, month, day) << endl;
    else
      cout << month << '/' << day << '/' << year << " is an invalid date.\n";
  }
  return 0;
}

UVa 10081 - Tight Words

Accepted date: 2013-01-02
Ranking (as of 2013-01-14): 956
Language: C++

/*
  UVa 10081 - Tight Words

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

#include <cstdio>
#include <cmath>

const int k_max = 9, n_max = 100;
double tight_words[n_max][k_max + 1];

int main()
{
  int k, n;
  while (scanf("%d %d", &k, &n) != EOF) {
    for (int i = 0; i <= k; i++)
      tight_words[0][i] = 1.0;
    for (int i = 1; i < n; i++)
      for (int j = 0; j <= k; j++) {
        tight_words[i][j] = tight_words[i - 1][j];
        if (j)
          tight_words[i][j] += tight_words[i - 1][j - 1];
        if (j < k)
          tight_words[i][j] += tight_words[i - 1][j + 1];
      }
      double tw = 0.0;
      for (int i = 0; i <= k; i++)
        tw += tight_words[n - 1][i];
      printf("%.5lf\n",
        (tw * 100.0) / pow(static_cast<double>(k + 1), static_cast<double>(n)));
  }
  return 0;
}

UVa 126 - The Errant Physicist

Accepted date: 2013-01-10
Ranking (as of 2013-01-14): 657
Language: C++

Used std::map to associate a term with its coefficient.

/*
  UVa 126 - The Errant Physicist

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

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

const int nr_chars_max = 80, nr_terms_max = 80;

struct term {
  int x_exp_; // x exponent
  int y_exp_; // y exponent

  bool operator<(const term& t) const
  {
    if (x_exp_ > t.x_exp_) // descending order of x exponent
      return true;
    else if (x_exp_ < t.x_exp_)
      return false;
    else
      return y_exp_ < t.y_exp_; // ascending order of y exponent
  }
};

bool add_term(map<term, int>& terms, const term& t, int coef)
{
  pair<map<term, int>::iterator, bool> result = terms.insert(make_pair(t, coef));
  if (!result.second)
    result.first->second += coef;
  return result.second;
}

int parse_terms(const char* s, map<term, int>& terms)
{
  const char* p = s;
  term t;
  t.x_exp_ = t.y_exp_ = 0;
  int coef = 1;
  while (*p) {
    if (*p == '-' || *p == '+') {
      if (p > s)
        add_term(terms, t, coef);
      t.x_exp_ = t.y_exp_ = 0;
      coef = (*p == '-') ? -1 : 1;
      p++;
    }
    else if (isdigit(*p)) {
      char* q;
      int d = strtol(p, &q, 10);
      if (p > s) {
        if (*(p - 1) == 'x')
          t.x_exp_ = d;
        else if (*(p - 1) == 'y')
          t.y_exp_ = d;
        else
          coef *= d;
      }
      else
        coef = d;
      p = q;
    }
    else {
      if (*p == 'x' && !t.x_exp_)
        t.x_exp_ = 1;
      else if (*p == 'y' && !t.y_exp_)
        t.y_exp_ = 1;
      p++;
    }
  }
  if (p  > s)
    add_term(terms, t, coef);
  return static_cast<int>(terms.size());
}

#ifdef DEBUG
void print_terms(const map<term, int>& terms)
{
  bool printed = false;
  for (map<term, int>::const_iterator i = terms.begin(), e = terms.end();
    i != e; ++i) {
    if (printed)
      putchar(' ');
    else
      printed = true;
    printf("%dx%dy%d", i->second, i->first.x_exp_, i->first.y_exp_);
  }
  putchar('\n');
}
#endif

int print_number(int n, char* p)
{
  char* q = p;
  do {
    *q++ = (n % 10) + '0';
    n /= 10;
  } while (n);
  int length = q - p;
  for (q--; p < q; p++, q--)
    swap(*p, *q);
  return length;
}

int main()
{
  while (true) {
    char s[nr_chars_max + 1];
    gets(s);
    if (s[0] == '#')
      break;
    map<term, int> one_terms, other_terms;
    int nr_one_terms = parse_terms(s, one_terms);
    gets(s);
    int nr_other_terms = parse_terms(s, other_terms);
#ifdef DEBUG
    print_terms(one_terms);
    print_terms(other_terms);
#endif
    map<term, int> result_terms;
    for (map<term, int>::const_iterator i = one_terms.begin(),
      ie = one_terms.end(); i != ie; ++i)
      for (map<term, int>::const_iterator j = other_terms.begin(),
        je = other_terms.end(); j != je; ++j) {
        term t;
        t.x_exp_ = i->first.x_exp_ + j->first.x_exp_;
        t.y_exp_ = i->first.y_exp_ + j->first.y_exp_;
        int coef = i->second * j->second;
        add_term(result_terms, t, coef);
      }
#ifdef DEBUG
    print_terms(result_terms);
#endif
    char es[nr_chars_max + 1], ts[nr_chars_max + 1];
    memset(es, ' ', nr_chars_max);
    memset(ts, ' ', nr_chars_max);
    int si = 0;
    for (map<term, int>::const_iterator i = result_terms.begin(),
      ie = result_terms.end(); i != ie; ++i) {
      int coef = i->second;
      if (!coef)
        continue;
      const term& t = i->first;
      // print the coefficient
      if (si) {
        ts[si++] = ' '; ts[si++] = (coef < 0) ? '-' : '+'; ts[si++] = ' ';
      }
      else if (coef < 0)
        ts[si++] = '-';
      coef = abs(coef);
      if (coef > 1 || !t.x_exp_ && !t.y_exp_)
        si += print_number(abs(coef), &ts[si]);
      if (t.x_exp_ || t.y_exp_) {
        if (t.x_exp_) {
          ts[si++] = 'x';
          if (t.x_exp_ > 1)
            si += print_number(t.x_exp_, &es[si]);
        }
        if (t.y_exp_) {
          ts[si++] = 'y';
          if (t.y_exp_ > 1)
            si += print_number(t.y_exp_, &es[si]);
        }
      }
    }
    es[si] = ts[si] = '\0';
    puts(es);
    puts(ts);
  }
  return 0;
}

UVa 153 - Permalex

Accepted date: 2013-01-02
Ranking (as of 2013-01-14): 1251
Language: C++

/*
  UVa 153 - Permalex

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

#include <cstdio>
#include <cstring>

const int nr_letters = 26, nr_chars_max = 30;

int permutation_of_repeated_chars(int length, int letters[])
{
  int nr_denominators = 0, denominators[nr_chars_max];
  for (int i = 0; i < nr_letters; i++)
    for (int j = 2; j <= letters[i]; j++)
      denominators[nr_denominators++] = j;
  long long n = 1, d = 1;
  for (int i = 2; i <= length; i++) {
    n *= i;
    if (nr_denominators > 0)
      d *= denominators[--nr_denominators];
    if (d != 1 && !(n % d)) {
      n /= d;
      d = 1;
    }
  }
  return static_cast<int>(n);
}

int main()
{
  int letters[nr_letters];
    // letters[i] is the number of occurrences of ('a' + i)
  while (true) {
    char s[nr_chars_max + 1];
    scanf("%s", s);
    if (s[0] == '#')
      break;
    memset(letters, 0, sizeof(letters));
    int length = strlen(s);
    for (int i = 0; i < length; i++)
      letters[s[i] - 'a']++;
    int sequence = 1;
    for (int i = 0; i < length; i++) {
      int j;
      for (j = 0; j < s[i] - 'a'; j++)
        if (letters[j]) {
          letters[j]--;
          sequence += permutation_of_repeated_chars(length - i - 1, letters);
          letters[j]++;
        }
      letters[j]--;
    }
    printf("%10d\n", sequence);
  }
  return 0;
}

UVa 232 - Crossword Answers

Accepted date: 2013-01-05
Ranking (as of 2013-01-14): 560
Language: C++

/*
  UVa 232 - Crossword Answers

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

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

int main()
{
  const int r_max = 10, c_max = 10;
  char grid[r_max][c_max];
  int definitions[r_max][c_max];
  for (int pn = 1; ; pn++) {
    int r, c;
    cin >> r;
    if (!r)
      break;
    cin >> c;
    for (int i = 0, n = 1; i < r; i++)
      for (int j = 0; j < c; j++) {
        cin >> grid[i][j];
        definitions[i][j] = (grid[i][j] != '*' &&
          (!i || !j || grid[i - 1][j] == '*' || grid[i][j - 1] == '*')) ? 
          n++ : 0;
      }
    if (pn > 1)
      cout << endl;
    cout << "puzzle #" << pn << ":\n";
    cout << "Across\n";
    for (int i = 0; i < r; i++)
      for (int j = 0; j < c; j++)
        if (definitions[i][j] && (!j || grid[i][j - 1] == '*')) {
          cout << setfill(' ') << setw(3) << definitions[i][j] << '.';
          for (int k = j; k < c; k++) {
            if (grid[i][k] == '*')
              break;
            else
              cout << grid[i][k];
          }
          cout << endl;
        }
    cout << "Down\n";
    for (int i = 0; i < r; i++)
      for (int j = 0; j < c; j++)
        if (definitions[i][j] && (!i || grid[i - 1][j] == '*')) {
          cout << setfill(' ') << setw(3) << definitions[i][j] << '.';
          for (int k = i; k < r; k++) {
            if (grid[k][j] == '*')
              break;
            else
              cout << grid[k][j];
          }
          cout << endl;
        }
  }
  return 0;
}

UVa 11074 - Draw Grid

Accepted date: 2013-01-10
Ranking (as of 2013-01-14): 52
Language: C++

/*
    UVa 11074 - Draw Grid

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

#include <cstdio>
#include <cstring>

const int s_max = 20, t_max = 20, n_max = 20;
char line[(s_max + t_max) * n_max + t_max + 1];

int main()
{
    for (int case_nr = 1; ; case_nr++) {
        int s, t, n;
        scanf("%d %d %d", &s, &t, &n);
        if (!s && !t && !n)
            break;
        printf("Case %d:\n", case_nr);

        int l = (s + t) * n + t;
        line[l] = '\0';
        for (int i = 0; i < n; i++) {
            memset(line, '*', l);
            for (int j = 0; j < t; j++)
                puts(line);
            for (int j = t, k = 0; k < n; j += s + t, k++)
                memset(line + j, '.', s);
            for (int j = 0; j < s; j++)
                puts(line);
        }
        memset(line, '*', l);
        for (int j = 0; j < t; j++)
            puts(line);
        putchar('\n');
    }
    return 0;
}

UVa 10063 - Knuth's Permutation

Accepted date: 2013-01-07
Ranking (as of 2013-01-14): 25
Language: C++

/*
    UVa 10063 - Knuth's Permutation

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

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

const int nr_chars_max = 10;

void knuths_permutation(int n, int i, const char* s, char* t)
{
    if (i == n) {
        t[n] = '\0';
        printf("%s\n", t);
    }
    else {
        char u[nr_chars_max + 1];
        u[0] = s[i];
        memcpy(&u[1], t, i);
        knuths_permutation(n, i + 1, s, u);
        for (int j = 0; j < i; j++) {
            swap(u[j], u[j + 1]);
            knuths_permutation(n, i + 1, s, u);
        }
    }
}

int main()
{
    bool printed = false;
    char s[nr_chars_max + 1], t[nr_chars_max + 1];
    while (scanf("%s", s) != EOF) {
        if (printed)
            putchar('\n');
        else
            printed = true;
        knuths_permutation(strlen(s), 0, s, t);
    }
    return 0;
}