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

UVa 404 - Radar Scopes

Accepted date: 2011-06-24
Ranking (as of 2013-08-14): 56 out of 118
Language: C++

/*
  UVa 404 - Radar Scopes

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

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <map>
#include <cfloat>
#include <cmath>
using namespace std;

const double pi = 2.0 * acos(0.0); // 3.14159265358979323846
const double radar_radius = 10.0; // in miles
const double radar_sweep_cycle = 5.0; // inseconds

enum warnings {
  unknown = -2, no_warnings, equipment_warning, new_intrusion, new_aloft,
  domain_exited, domain_loss
};

const char* warning_messages[] = {
  "equipment warning", "new intrusion", "new aloft", "domain exited",
  "domain loss"
};

struct airplane {
  string s_squawk; // squawk number in string
  int squawk; // squawk number, between 0 and 32767
  double azimuth; // in degrees between 0 and 360
  double distance; // in miles
  double speed; // in miles/hour
  int warning;
};

bool is_outside_of_radar_scope(const airplane& ap)
{
  return ap.distance +
    ap.speed * 1.10 * radar_sweep_cycle / 3600.0 >= radar_radius;
}

bool is_equipment_warning(const airplane& first, const airplane& second)
{
  double angle = (first.azimuth - second.azimuth) * pi / 180.0;
  double distance =sqrt(first.distance * first.distance +
    second.distance * second.distance
    - 2.0 * first.distance * second.distance * cos(angle));
  double measured_speed = distance * 3600.0 / radar_sweep_cycle;
  double average_speed = (first.speed + second.speed) / 2.0;
  return average_speed < measured_speed * 0.90 ||
    average_speed > measured_speed * 1.10;
}

int main(int /* argc */, char** /* argv */)
{
  int senario_nr = 1;
  int n1, n2;
  while (cin >> n1) {
    airplane ap;
    ap.warning = unknown;
    map<int, airplane> airplanes; // indexed by squawk numbers
    for (int i = 0; i < n1; i++) {
      cin >> ap.s_squawk;
      istringstream iss(ap.s_squawk);
      iss >> dec >> ap.squawk;
      cin >> dec >> ap.azimuth >> ap.distance >> ap.speed;
      airplanes.insert(make_pair(ap.squawk, ap));
    }
    cin >> n2;
    for (int i = 0; i < n2; i++) {
      cin >> ap.s_squawk;
      istringstream iss(ap.s_squawk);
      iss >> dec >> ap.squawk;
      cin >> dec >> ap.azimuth >> ap.distance >> ap.speed;
      map<int, airplane>::iterator j = airplanes.find(ap.squawk);
      if (j != airplanes.end())
        j->second.warning = (is_equipment_warning(j->second, ap)) ?
          equipment_warning : no_warnings;
      else { // not found in the first sweep
        ap.warning = (is_outside_of_radar_scope(ap)) ?
          new_intrusion : new_aloft;
        airplanes.insert(make_pair(ap.squawk, ap));
      }
    }
    cout << "Scenario # " << senario_nr++ << endl;
    for (map<int, airplane>::iterator i = airplanes.begin();
      i != airplanes.end(); i++) {
      airplane& ap = i->second;
      if (ap.warning == unknown) // not found in the second sweep
        ap.warning = (is_outside_of_radar_scope(ap)) ?
          domain_exited : domain_loss;
      if (ap.warning > no_warnings)
        cout << setw(5) << setfill(' ') <<
          ap.s_squawk << " -- " << warning_messages[ap.warning] << endl;
    }
    cout << endl; // after each scenario, print a blank line
  }
  return 0;
}

UVa 10149 - Yahtzee

Accepted date: 2011-07-10
Language: C++

/*
  2.8.8 Yahtzee
  PC/UVa IDs: 110208/10149, Popularity: C, Success rate: average Level: 3

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

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

enum categories {
  ct_not_applied = -1,
  ct_ones, ct_twos, ct_threes, ct_fours, ct_fives, ct_sixes,
  ct_chance, ct_three_of_a_kind, ct_four_of_a_kind,
  ct_five_of_a_kind, ct_short_straight, ct_long_straight, ct_full_house
};

const int nr_dies = 5; // number of dies
const int nr_rounds = 13; // number of rounds
const int nr_categories = ct_full_house - ct_ones + 1; // number of categories
const int min_sum_for_bonus = 63; // min. sum of first six categories for bonus
const int bonus_point = 35; // bonus point

int category_chance(const vector<int>& dies) // sum of all dies
{
  return accumulate(dies.begin(), dies.end(), 0);
}

int category_three_of_a_kind(const vector<int>& dies)
  // sum of all dies, provided at least three have same value
{
  // note that dies is sorted in ascending order
  for (int i = 0; i < nr_dies - 2; i++)
    if (dies[i] == dies[i + 1] && dies[i + 1] == dies[i + 2])
      return category_chance(dies);
  return 0;
}

int category_four_of_a_kind(const vector<int>& dies)
  // sum of all dies, provided at least four have same value
{
  // note that dies is sorted in ascending order
  int j = (dies[0] == dies[1]) ? nr_dies - 2 : nr_dies - 1;
  for (int i = 1; i < j; i++)
    if (dies[i] != dies[i + 1])
      return 0;
  return category_chance(dies);
}

int category_five_of_a_kind(const vector<int>& dies)
  // 50 points, provided all five dies have same value
{
  // note that dies is sorted in ascending order
  return (dies[0] == dies[4]) ? 50 : 0;
}

int category_short_straight(const vector<int>& dies)
  // 25 points, provided four of the dies form a sequence
{
  int j = (dies[0] + 1 == dies[1]) ? nr_dies - 2 : nr_dies - 1;
  for (int i = 1; i < j; i++)
    if (dies[i] + 1 != dies[i + 1])
      return 0;
  return 25;
}

int category_long_straight(const vector<int>& dies)
  // 35 points, provided all dies form a sequence
{
  for (int i = 0; i < nr_dies - 1; i++)
    if (dies[i] + 1 != dies[i + 1])
      return 0;
  return 35;
}

int category_full_house(const vector<int>& dies)
  // 40 points, provided three of the dies are equal and 
  // the other two dies are also equal
{
  if (dies[0] != dies[1]) // the first two must be equal
    return 0;
  if (dies[1] == dies[2]) // the first three are equal
    return (dies[3] == dies[4]) ? 40 : 0; // the last two must be equal
  else
    return (dies[2] == dies[3] && dies[3] == dies[4]) ? 40 : 0;
      // the last three must be equal
}

int category_numbers(const vector<int>& dies, int n)
{
  return n * count(dies.begin(), dies.end(), n);
}

int category_ones(const vector<int>& dies) // sum of all ones thrown
{
  return category_numbers(dies, 1);
}

int category_twos(const vector<int>& dies) // sum of all twos thrown
{
  return category_numbers(dies, 2);
}

int category_threes(const vector<int>& dies) // sum of all threes thrown
{
  return category_numbers(dies, 3);
}

int category_fours(const vector<int>& dies) // sum of all fours thrown
{
  return category_numbers(dies, 4);
}

int category_fives(const vector<int>& dies) // sum of all fives thrown
{
  return category_numbers(dies, 5);
}

int category_sixes(const vector<int>& dies) // sum of all sixes thrown
{
  return category_numbers(dies, 6);
}

void caluculate_applicable_scores(const vector<int>& dies,
  vector<int>& scores)
{
  typedef int (*category_function)(const vector<int>&);
  const category_function category_functions[] = {
    category_ones, category_twos, category_threes, category_fours,
    category_fives, category_sixes,
    category_chance, category_three_of_a_kind, category_four_of_a_kind,
    category_five_of_a_kind,
    category_short_straight, category_long_straight, category_full_house
  };
  for (int i = ct_ones; i <= ct_full_house; i++) {
    int score = category_functions[i](dies);
    if (score)
      scores[i] = score;
  }
}

inline int get_score_index(int category)
{

  return 1 << (category + 16);
}

inline int get_score_index(int category, int score)
  // score index for the first six categories
{
/*
  if (score > min_sum_for_bonus)
    score = min_sum_for_bonus;
*/
  return 1 << (category + 16) | score;
}

inline int get_category_bitmap(int index)
{
  return index >> 16;
}

inline int get_score_for_bonus(int index)
{
  return index & 0xffff;
}

int get_applied_score(unsigned long long score, int category,
  const vector< vector<int> >& applicable_scores)
{
  int round = static_cast<int>((score >> (category * 4)) & 0xf);
  return (round == 0xf) ? 0 /* not applied */ :
    applicable_scores[round][category];
}

inline int get_total_of_score(unsigned long long score)
{
  return static_cast<int>((score >> 52) & 0xfff);
}

unsigned long long set_score(int round, int category,
  const vector< vector<int> >& applicable_scores)
{
  unsigned long long score = 0x000fffffffffffffULL;
  score &= ~(static_cast<unsigned long long>(0xf) << (category * 4));
  score |= static_cast<unsigned long long>(round) << (category * 4);
  score |=
    static_cast<unsigned long long>(applicable_scores[round][category]) << 52;
  return score;
}

unsigned long long change_score(unsigned long long score,
  int round, int category, int s)
{
  score &= ~(static_cast<unsigned long long>(0xf) << (category * 4));
  score |= static_cast<unsigned long long>(round) << (category * 4);
  score &= 0x000fffffffffffffULL;
  score |= static_cast<unsigned long long>(s) << 52;
  return score;
}

void add_to_scores(int index, unsigned long long score, map<int,
  unsigned long long>& scores)
{
  map<int, unsigned long long>::iterator i = scores.find(index);
  if (i != scores.end()) {
    if (get_total_of_score(i->second) < get_total_of_score(score))
      i->second = score;
  }
  else
    scores.insert(make_pair(index, score));
}

bool read_rounds_of_dies(vector< vector<int> >& applicable_scores)
{
  for (int i = 0; i < nr_rounds; i++) { // read the values of thirteen rounds
    vector<int> dies(nr_dies);
      // values of the five dies thrown, sorted in ascending order
    for (int j = 0; j < nr_dies; j++) { // read the values of the five dies
      if (!(cin >> dies[j]))
        return false; // end of input
    }
    sort(dies.begin(), dies.end());
    caluculate_applicable_scores(dies, applicable_scores[i]);
  }
  return true;
}

#ifdef DEBUG
void print_scores(const map<int, unsigned long long>& scores)
{
  map<int, unsigned long long>::const_iterator iend = scores.end();
  for (map<int, unsigned long long>::const_iterator i = scores.begin();
    i != iend; ++i)
    cerr << hex << setw(4) << setfill('0') <<
      get_category_bitmap(i->first) << '-' <<
      dec << setw(4) << setfill(' ') <<
      get_score_for_bonus(i->first) << ": " <<
      get_total_of_score(i->second) << endl;
  cerr << endl;
}
#endif

void caluculate_scores(vector< vector<int> >& applicable_scores,
  vector< map<int, unsigned long long> >& scores)
{
  for (int i = 0; i < nr_rounds; i++) {
    map<int, unsigned long long>& current_scores = scores[i % 2];
    map<int, unsigned long long>& previous_scores = scores[(i + 1) % 2];
    current_scores = previous_scores;

    for (int j = 0; j < nr_categories; j++) {
      if (applicable_scores[i][j] == -1) // not applied to any categories
        continue;

      int pi, ci; // previous and current indices
      unsigned long long ps, cs; // prevous and current scores
      // insert or update a pair of category and its score on its own
      ci = (j < ct_chance) ?
        get_score_index(j, applicable_scores[i][j]) : get_score_index(j);
      cs = set_score(i, j, applicable_scores);
      add_to_scores(ci, cs, current_scores);

      // add the score to the existing pairs of categories and thier scores
      map<int, unsigned long long>::iterator k, kend = previous_scores.end();
      for (k = previous_scores.begin(); k != kend; ++k) {
        pi = k->first; ps = k->second;
        int ts = get_total_of_score(ps); // totoal of the previous score
        // score for category j of the previous score
        int as = (pi & get_score_index(j)) ?
          // category j is applied to any of the previous rounds
          get_applied_score(ps, j, applicable_scores) : 0;
        if (j > ct_sixes) {
          // replace category j with current round i and update the total score
          cs = change_score(ps, i, j, ts + applicable_scores[i][j] - as);
          add_to_scores(pi | get_score_index(j), cs, current_scores);
        }
        else {
          // modifying the socre for category j of the prevous score also 
          // entails updating the lower 16-bits of index.
          ci = get_score_index(j, get_score_for_bonus(pi) +
            applicable_scores[i][j] - as);
          ci |= get_category_bitmap(pi) << 16;
          cs = change_score(ps, i, j, ts + applicable_scores[i][j] - as);
          add_to_scores(ci, cs, current_scores);
        }
      }
    }
#ifdef DEBUG
    cerr << i + 1 << " rounds, " <<
      current_scores.size() << " scores\n";
//    print_scores(current_scores);
#endif
  }
}

int get_max_score(map<int, unsigned long long>& scores,
  pair<int, unsigned long long>& s)
{
  int max_ts = -1;
  map<int, unsigned long long>::const_iterator iend = scores.end();
  for (map<int, unsigned long long>::const_iterator i = scores.begin();
    i != iend; ++i) {
    int ts = get_total_of_score(i->second);
    if (get_score_for_bonus(i->first) >= min_sum_for_bonus)
      ts += bonus_point;
        // a bonus of 35 points if the sum of the first six categories is 
        // 63 or greater
    if (max_ts < ts) {
      max_ts = ts; s = *i;
    }
  }
  return max_ts;
}

void print_scores(const pair<int, unsigned long long>& s,
  const vector< vector<int> >& applicable_scores)
{
  int ts = get_total_of_score(s.second);
  unsigned long long ri = s.second;
  for (int i = 0; i < nr_categories; i++, ri >>= 4) {
    // print the score for each category
    int r = (ri & 0xf);
    cout << ((r != 0x0f) ? applicable_scores[r][i] : 0) << ' ';
  }
  // print the bonus score
  if (get_score_for_bonus(s.first) >= min_sum_for_bonus) {
    cout << "35 ";
    ts += bonus_point;
  }
  else
    cout << "0 ";
  cout << ts << endl;
}

int main(int /* argc */, char ** /* argv */)
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  while (true) {
    vector< vector<int> >
      applicable_scores(nr_rounds, vector<int>(nr_categories, -1));
      // applicable_scores[i][j] is the score when the j-th category is 
      // applied to the i-th round, 
      // or -1 if the j-th category cannot be applied.
    if (!read_rounds_of_dies(applicable_scores))
      break;
    vector< map<int, unsigned long long> > scores(2);
/*
  key is an index whose:
    higher 16-bits are bitmaps of applied categories, 
      in which i-th bit is set if the i-th categoriy 
      from categories enumeration is applied.
    lower 16-bits are the sum of first six categories' 
      (i.e., ones, twos, threes, fours, fives, and sixes) scores.
  value is the score:
    bit (4 * i) - bit (4 * i + 3) is the round index if the i-th category is 
      applied to the round, or 0xf if it is not applied.
    bit 52 - bit 63 is the total scores.
*/
    caluculate_scores(applicable_scores, scores);
    map<int, unsigned long long>& current_scores = scores[(nr_rounds - 1) % 2];
    pair<int, unsigned long long> s;
    get_max_score(current_scores, s);
    print_scores(s, applicable_scores);
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10646 - What is the Card?

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

/*
  UVa 10646 - What is the Card?

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

#include <cstdio>
#include <cctype>

int main()
{
  const int nr_cchars = 2, nr_pcards_max = 27, nr_hcards = 25;
  char pile[nr_pcards_max][nr_cchars + 1], hand[nr_hcards][nr_cchars + 1];
  int t;
  scanf("%d\n", &t);
  for (int sn = 1; sn <= t; sn++) {
    for (int i = 0; i < nr_pcards_max; i++)
      scanf("%s", pile[i]);
    for (int i = 0; i < nr_hcards; i++)
      scanf("%s", hand[i]);
    int x, y = 0, nr_pcards = nr_pcards_max;
    for (int i = 0; i < 3; i++) {
      x = (isdigit(pile[nr_pcards - 1][0])) ? pile[nr_pcards - 1][0] - '0' : 10;
      y += x;
      nr_pcards -= 11 - x;
    }
    char* p = (y > nr_pcards) ? hand[y - 1 - nr_pcards] : pile[y - 1];
    printf("Case %d: %s\n", sn, p);
  }
  return 0;
}

Saturday, August 10, 2013

UVa 914 - Jumping Champion

Accepted date: 2013-08-10
Ranking (as of 2013-08-10): 154 out of 839
Language: C++

/*
  UVa 914 - Jumping Champion

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

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

const int n_max = 1000000;
bool not_primes[n_max + 1]; // not_primes[i] is true if i is not a prime

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 main()
{
  sieve_of_eratosthenes();
  int nr_primes = 0, nr_diffs = 0;
  for (int i = 2, pi = 0; i <= n_max; i++)
    if (!not_primes[i]) {
      if (nr_primes)
        nr_diffs = max(nr_diffs, i - pi);
      nr_primes++;
      pi = i;
    }
#ifdef DEBUG
  cout << nr_primes << ' ' << nr_diffs << endl;
#endif
  vector<int> primes(nr_primes);
  for (int i = 2, pi = 0; i <= n_max; i++)
    if (!not_primes[i])
      primes[pi++] = i;

  int t;
  cin >> t;
  while (t--) {
    int l, u;
    cin >> l >> u;
    bool no_jumping_champion = false;
    int diff = 0;
    if (u < primes[0] || l > primes[nr_primes - 1])
      no_jumping_champion = true; // no primes between l and u
    else {
      if (u > primes[nr_primes - 1])
        u = primes[nr_primes - 1];
      int li = distance(primes.begin(),
        lower_bound(primes.begin(), primes.end(), l)),
        ui = distance(primes.begin(),
          lower_bound(primes.begin(), primes.end(), u));
      if (primes[ui] != u)
        ui--;
      if (ui - li > 0) {
        vector<int> diffs(nr_diffs + 1, 0);
          // diffs[i] is the number of occurrences of difference i
        for (int i = li + 1; i <= ui; i++)
          diffs[primes[i] - primes[i - 1]]++;
        int max_occurences = 0;
        for (int i = 1; i <= nr_diffs; i++)
          max_occurences = max(max_occurences, diffs[i]);
        int nr_max_occurences = 0;
        for (int i = 1; i <= nr_diffs; i++)
          if (diffs[i] == max_occurences) {
            diff = i;
            if (++nr_max_occurences > 1)
              break;
          }
        if (nr_max_occurences > 1)
          no_jumping_champion = true;
      }
      else
        no_jumping_champion = true;
    }
    if (no_jumping_champion)
      cout << "No jumping champion\n";
    else
      cout << "The jumping champion is " << diff << endl;
  }
  return 0;
}

Sunday, August 4, 2013

UVa 10702 - Travelling Salesman

Accepted date: 2013-08-04
Ranking (as of 2013-08-04): 30 out of 996
Language: C++

/*
  UVa 10702 - Travelling Salesman

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

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

const int c_max = 100, t_max = 1000;
int tp[t_max + 1][c_max + 1]; // tp[k][i] is the k-th total profit of city i
int p[c_max + 1][c_max + 1]; // p[i][j] is the profit when moving from i to j

int main()
{
  while (true) {
    int c, s, e, t;
    scanf("%d %d %d %d", &c, &s, &e, &t);
    if (!c && !s && !e && !t)
      break;
    for (int i = 1; i <= c; i++)
      for (int j = 1; j <= c; j++)
        scanf("%d", &p[i][j]);
    for (int i = 1; i <= c; i++)
      tp[1][i] = p[s][i];
    for (int k = 2; k <= t; k++)
      for (int i = 1; i <= c; i++) {
        int max_p = 0;
        for (int j = 1; j <= c; j++)
          max_p = max(max_p, tp[k - 1][j] + p[j][i]);
        tp[k][i] = max_p;
      }
    int max_tp = 0;
    for (int i = 1; i <= e; i++) {
      int j;
      scanf("%d", &j);
      max_tp = max(max_tp, tp[t][j]);
    }
    printf("%d\n", max_tp);
  }
  return 0;
}

Saturday, August 3, 2013

UVa 152 - Tree's a Crowd

Accepted date: 2011-07-26
Ranking (as of 2013-08-03): 229 out of 1845
Language: C++

/*
  UVa 152 - Tree's a Crowd

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

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

const int nr_trees_max = 5000, nr_dimensions = 3;

struct tree_comparator
{
  int index_;
  tree_comparator(int index) : index_(index) {}
  bool operator() (const vector<int>& i, const vector<int>& j) const
    {return i[index_] < j[index_];}
};

double tree_distance(const vector<int>& i, const vector<int>& j)
{
  double d = 0.0;
  for (int k = 0; k < nr_dimensions; k++)
    d += (i[k] - j[k]) * (i[k] - j[k]);
  return sqrt(d);
}

int main()
{
  vector< vector<int> > trees(nr_trees_max, vector<int>(nr_dimensions));
  int n = 0;
  for ( ; ; n++) {
    int x, y, z;
    cin >> x >> y >> z;
    if (!x && !y && !z)
      break;
    trees[n][0] = x; trees[n][1] = y; trees[n][2] = z;
  }
  trees.resize(n);
  for (int i = 0; i < nr_dimensions; i++)
    stable_sort(trees.begin(), trees.end(), tree_comparator(i));
  const int nr_bins = 10;
  vector<int> histogram(nr_bins, 0);
  for (int i = 0; i < n; i++) {
    const vector<int>& t = trees[i];
    int d = numeric_limits<int>::max();
    for (int j = 0; j < nr_dimensions; j++) {
      for (int k = i - 1; k >= 0 && trees[k][j] >= t[j] - 10; k--)
        d = min(d, static_cast<int>(tree_distance(t, trees[k])));
      for (int k = i + 1; k < n && trees[k][j] <= t[j] + 10; k++)
        d = min(d, static_cast<int>(tree_distance(t, trees[k])));
    }
    if (d < 10)
      histogram[d]++;
  }
  for (int i = 0; i < nr_bins; i++)
    cout << setw(4) << setfill(' ') << histogram[i];
  cout << endl;
  return 0;
}

UVa 550 - Multiplying by Rotation

Accepted date: 2011-08-06
Ranking (as of 2013-08-03): 250 out of 940
Language: C++

/*
  UVa 550 - Multiplying by Rotation

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

#include <iostream>
using namespace std;

int main()
{
  int base, first_factor, multiplier;
  while (cin >> base >> first_factor >> multiplier) {
    int n = 0, multiplicand = first_factor;
    for (int carry = 0; ; n++) {
      int product = multiplicand * multiplier + carry;
      carry = product / base;
      if (!carry && product == first_factor)
        break;
      multiplicand = product % base;
    }
    cout << n + 1 << endl;
  }
  return 0;
}

UVa 784 - Maze Exploration

Accepted date: 2011-08-27
Ranking (as of 2013-08-03): 34 out of 2398
Language: C++

/*
  UVa 784 - Maze Exploration

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

#include <cstdio>
#include <cstdlib>

const int nr_chars_per_line_max = 80, nr_lines_max = 30;

int get_start(const char* s)
{
  bool separation_line = true;
  for (const char* p = s; *p; p++) {
    if (*p == '*')
      return p - s;
    else if (*p != '_')
      separation_line = false;
  }
  return (separation_line) ? -1 : 0;
}

void explore_maze(int i, int j,
  char maze[nr_lines_max + 1][nr_chars_per_line_max + 1])
{
  maze[i][j] = '#';
  if (maze[i - 1][j] == ' ') // upper
    explore_maze(i - 1, j, maze);
  if (maze[i][j - 1] == ' ') // left
    explore_maze(i, j - 1, maze);
  if (maze[i][j + 1] == ' ') // right
    explore_maze(i, j + 1, maze);
  if (maze[i + 1][j] == ' ') // lower
    explore_maze(i + 1, j, maze);
}

int main()
{
  char maze[nr_lines_max + 1][nr_chars_per_line_max + 1];
  gets(maze[0]);
  int nr_mazes = atoi(maze[0]);
  int start_i, start_j;
  while (nr_mazes--) {
    int nr_lines = 0;
    while (true) {
      gets(maze[nr_lines]);
      int j = get_start(maze[nr_lines]);
      if (j > 0) {
        start_i = nr_lines; start_j = j;
      }
      nr_lines++;
      if (j == -1) // reach at a separation line
        break;
    }
    explore_maze(start_i, start_j, maze);
    for (int i = 0; i < nr_lines; i++)
      puts(maze[i]);
  }
  return 0;
}

UVa 11205 - The Broken Pedometer

Accepted date: 2011-08-30
Ranking (as of 2013-08-03): 88 out of 754
Language: C++

/*
  UVa 11205 - The Broken Pedometer

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

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

bool are_symbols_distinguishable(int mask, int mask_max, int nr_symbols,
  const vector<int>& symbols)
{
  vector<bool> masked_symbols(mask_max, false);
  for (int i = 0; i < nr_symbols; i++) {
    int j = symbols[i] & mask;
    if (masked_symbols[j])
      return false;
    masked_symbols[j] = true;
  }
  return true;
}

int count_leds(int i, int nr_leds)
{
  int count = 0;
  for (int j = 0; j < nr_leds; j++, i >>= 1)
    if (i & 1)
      count++;
  return count;
}

int main()
{
  int nr_problems;
  cin >> nr_problems;
  while (nr_problems--) {
    int nr_leds, nr_symbols;
    cin >> nr_leds >> nr_symbols;
    vector<int> symbols(nr_symbols);
    for (int i = 0; i < nr_symbols; i++) {
      int s = 0;
      for (int j = 0; j < nr_leds; j++) {
        char c;
        cin >> c;
        s <<= 1;
        if (c == '1')
          s |= 1;
      }
      symbols[i] = s;
    }
    int nr = nr_leds;
    if (!nr_symbols)
      nr = 0;
    else if (nr_symbols == 1) {
      nr = (symbols[0]) ? 1 : 0;
    }
    else {
      int min_nr_leds = static_cast<int>(
        ceil(log10(static_cast<double>(nr_symbols)) / log10(2.0)));
        // min. number of LEDs to distinguish the symbols
      for (int i = 1,
        i_max = static_cast<int>(pow(2.0, static_cast<double>(nr_leds)));
        i < i_max; i++)
        if (are_symbols_distinguishable(~i, i_max, nr_symbols, symbols)) {
          nr = min(nr, nr_leds - count_leds(i, nr_leds));
          if (nr == min_nr_leds)
            break;
        }
    }
    cout << nr << endl;
  }
  return 0;
}

UVa 301 - Transportation

Accepted date: 2011-09-08
Ranking (as of 2013-08-03): 193 out of 1117
Language: C++

/*
  UVa 301 - Transportation

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

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

struct order // ticket order
{
  int start; // starting station
  int destination; // destination station
  int nr_passengers; // number of passengers
  int earning; // earning if order is accepted
};

bool compare_order(const order& i, const order& j)
{
  return i.start < j.start;
}

enum order_state {unprocessed, accepted, rejected};

void accept_orders(int capacity, int last_station, int current_station,
  int next_order /* order index to be exmained */,
  int nr_orders, const vector<order>& orders,
  vector<order_state>& order_states, int earning, int& max_earning)
{
  // when arriving at the current station, recaluclate the capacity
  if (!next_order) {
    for (int i = 0; i < nr_orders; i++)
      if (orders[i].destination == current_station &&
        order_states[i] == accepted)
        // passengers get off at the current station
        capacity += orders[i].nr_passengers;
  }
  if (current_station == last_station) {
    if (earning > max_earning)
      max_earning = earning;
    return;
  }
  else {
    int remainig_earning = 0;
    for (int i = next_order; i < nr_orders; i++)
      if (orders[i].start >= current_station)
        remainig_earning += orders[i].earning;
    if (earning + remainig_earning <= max_earning)
      return;
  }

  // try to take the passengers on board
  bool processed = false;
  if (capacity > 0) {
    for (int i = next_order; i < nr_orders; i++)
      if (orders[i].start == current_station && order_states[i] == unprocessed) {
        processed = true;
        if (orders[i].nr_passengers <= capacity) {
          order_states[i] = accepted;
          accept_orders(capacity - orders[i].nr_passengers, last_station,
            current_station, i + 1, nr_orders, orders, order_states, 
            earning + orders[i].earning, max_earning);
        }
        order_states[i] = rejected;
        accept_orders(capacity, last_station, current_station, i + 1,
          nr_orders, orders, order_states, earning, max_earning);
        order_states[i] = unprocessed;
        break;
      }
  }
  if (!processed) // all of the orders for the current station has been processed
    accept_orders(capacity, last_station, current_station + 1, 0,
      nr_orders, orders, order_states, earning, max_earning);
}

int main()
{
  while (true) {
    int capacity, last_station, nr_orders;
    cin >> capacity >> last_station >> nr_orders;
    if (!capacity && !last_station && !nr_orders)
      break;
    vector<order> orders(nr_orders);
    for (int i = 0; i < nr_orders; i++) {
      cin >> orders[i].start >> orders[i].destination >>
        orders[i].nr_passengers;
      orders[i].earning = orders[i].nr_passengers *
        (orders[i].destination - orders[i].start);
    }
    sort(orders.begin(), orders.end(), compare_order);
      // sort the orders in ascending order of starting station
    int max_earning = -1;
    vector<order_state> order_states(nr_orders, unprocessed);
    accept_orders(capacity, last_station, 0, 0, nr_orders, orders, order_states,
      0, max_earning);
    cout << max_earning << endl;
  }
  return 0;

}

UVa 10422 - Knights in FEN

Accepted date: 2011-09-15
Ranking (as of 2013-08-03): 159 out of 1133
Language: C++

/*
  UVa 10422 - Knights in FEN

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

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

const int nr_rows = 5, nr_columns = 5;
const int nr_moves_max = 10;

void move_knights(int nr_moves, int& min_nr_moves, int psi, int psj,
  int si, int sj, char chessboard[nr_rows][nr_columns]);

void swap_space(int nr_moves, int& min_nr_moves, int psi, int psj,
  int si, int sj, int ki, int kj, char chessboard[nr_rows][nr_columns])
{
  if (ki < 0 || ki >= nr_rows || kj < 0 || kj >= nr_columns)
    ;
  else if (psi == ki && psj == kj)
    ;
  else {
    swap(chessboard[si][sj], chessboard[ki][kj]);
    move_knights(nr_moves + 1, min_nr_moves, si, sj, ki, kj, chessboard);
    swap(chessboard[ki][kj], chessboard[si][sj]);
  }
}

int are_knights_at_final_positions(const char chessboard[nr_rows][nr_columns])
{
  const char final_positions[nr_rows][nr_columns] = {
    {'1', '1', '1', '1', '1'},
    {'0', '1', '1', '1', '1'},
    {'0', '0', ' ', '1', '1'},
    {'0', '0', '0', '0', '1'},
    {'0', '0', '0', '0', '0'}
  };
  int nr_differences = 0;
  for (int i = 0; i < nr_rows; i++)
    for (int j = 0; j < nr_columns; j++)
      if (chessboard[i][j] != final_positions[i][j])
        nr_differences++;
  return nr_differences;
}

void move_knights(int nr_moves, int& min_nr_moves, int psi, int psj,
  int si, int sj, char chessboard[nr_rows][nr_columns])
{
  if (nr_moves > nr_moves_max)
    return;
  int nr_differences = are_knights_at_final_positions(chessboard);
  if (!nr_differences) {
#ifdef DEBUG
  cout << "number of moves = " << nr_moves << endl;
#endif
    if (nr_moves < min_nr_moves)
      min_nr_moves = nr_moves;
    return;
  }
  else if (nr_differences - 2 > nr_moves_max - nr_moves)
    return; // no need to further search
  else {
    // from the current space position (si, sj), swap a knight with the space
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si - 2, sj - 1,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si - 2, sj + 1,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si - 1, sj - 2,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si - 1, sj + 2,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si + 1, sj - 2,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si + 1, sj + 2,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si + 2, sj - 1,
      chessboard);
    swap_space(nr_moves, min_nr_moves, psi, psj, si, sj, si + 2, sj + 1,
      chessboard);
  }
}

int main()
{
  int n;
  cin >> n;
  string line;
  getline(cin, line); // skip '\n'
  while (n--) {
    char chessboard[nr_rows][nr_columns];
    int si, sj;
    for (int i = 0; i < nr_rows; i++) {
      getline(cin, line);
      for (int j = 0; j < nr_columns; j++) {
        chessboard[i][j] = line[j];
        if (chessboard[i][j] == ' ') {
          si = i; sj = j;
        }
      }
    }
    int min_mr_moves = nr_moves_max + 1;
    move_knights(0, min_mr_moves, -1, -1, si, sj, chessboard);
    if (min_mr_moves > nr_moves_max)
      cout << "Unsolvable in less than 11 move(s).\n";
    else
      cout << "Solvable in " << min_mr_moves <<" move(s).\n";
  }
  return 0;
}

UVa 10391 - Compound Words

Accepted date: 2011-10-04
Ranking (as of 2013-08-03): 275 out of 1029
Language: C++

/*
  UVa 10391 - Compound Words

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

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

const int nr_words_max = 120000;
char* pwords[nr_words_max]; // pwords[i] is the i-th word string

int compare_word(const void* s, const void* t)
{
  return strcmp(*(const char**)s, *(const char**)t);
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start = clock();
#endif
  int nr_words = 0;
  size_t max_word_length = 0;
  string s;
  while (cin >> s) {
    size_t length = s.length();
    max_word_length = max(max_word_length, length);
    pwords[nr_words] = new char[length + 1];
    strcpy(pwords[nr_words], s.c_str());
    nr_words++;
  }
  char* pw = new char[max_word_length + 2];
  for (int i = 0; i < nr_words; i++) {
    strcpy(pw + 1, pwords[i]);
    for (char *qw = pw, *rw = pw + 2; *rw; qw++, rw++) {
      *qw = *(qw + 1); *(qw + 1) = '\0'; // divide the word by inserting a '\0'
      if (bsearch(&pw, pwords, nr_words, sizeof(char*), compare_word) &&
        bsearch(&rw, pwords, nr_words, sizeof(char*), compare_word)) {
        cout << pwords[i] << endl;
        break;
      }
    }
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 11218 - KTV

Accepted date: 2011-10-06
Ranking (as of 2013-08-03): 128 out of 704
Language: C++

/*
  UVa 11218 - KTV

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

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

int main()
{
  for (int c = 1; ; c++) {
    int n;
    cin >> n;
    if (!n)
      break;
    vector<int> combinations(n, 0);
      // combinations[i] is the i-th combination in which 
      // bits corresponding to three people are set
    vector<int> scores(n);
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < 3; j++) {
        int k;
        cin >> k;
        combinations[i] |= 1 << (k - 1);
      }
      cin >> scores[i];
    }
    int max_score = -1;
    for (int i = 0; i < n; i++) {
      int cm = combinations[i], s = scores[i];
      for (int j = i + 1; j < n; j++) {
        if (cm & combinations[j])
          continue;
        cm |= combinations[j];
        s += scores[j];
        for (int k = j + 1; k < n; k++) {
          if (cm & combinations[k])
            continue;
          max_score = max(max_score, s + scores[k]);
        }
        cm &= ~combinations[j];
        s -= scores[j];
      }
    }
    cout << "Case " << c << ": " << max_score << endl;
  }
  return 0;
}