Saturday, June 25, 2016

UVa 11957 - Checkers

Accepted date: 2016-06-25
Run Time: 0.000
Ranking (as of 2016-06-25): 23 out of 408
Language: C++

/*
  UVa 11957 - Checkers

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

#include <cstdio>

const int N_max = 100, divisor = 1000007;

char board[N_max][N_max + 1];
int N, nr_paths[N_max][N_max];
  // nr_paths[y][x] is the number of paths to the cell (x, y)

int from_left(int y, int x, bool jumped)
{
  y++, x--;
  if (y < N && x >= 0) {
    if (board[y][x] != 'B')
      return nr_paths[y][x];
    else
      return (jumped) ? 0 : from_left(y, x, true);
  }
  else
    return 0;
}

int from_right(int y, int x, bool jumped)
{
  y++, x++;
  if (y < N && x < N) {
    if (board[y][x] != 'B')
      return nr_paths[y][x];
    else
      return (jumped) ? 0: from_right(y, x, true);
  }
  else
    return 0;
}

int main()
{
  int T;
  scanf("%d", &T);
  for (int t = 1; t <= T; t++) {
    scanf("%d", &N);
    int sy, sx;
    for (int y = 0; y < N; y++) {
      scanf("%s", board[y]);
      for (int x = 0; x < N; x++)
        if (board[y][x] == 'W')
          sy = y, sx = x;
    }
    for (int y = 0; y < N; y++)
      for (int x = 0; x < N; x++)
        nr_paths[y][x] = 0;
    nr_paths[sy][sx] = 1;
    for (int y = sy - 1; y >= 0; y--)
      for (int x = 0; x < N; x++)
        if (board[y][x] != 'B')
          nr_paths[y][x] = (from_left(y, x, false) + from_right(y, x, false)) % divisor;
    int nr = 0;
    for (int x  = 0; x < N; x++) {
      nr += nr_paths[0][x];
      nr %= divisor;
    }
    printf("Case %d: %d\n", t, nr);
  }
  return 0;
}

Monday, June 20, 2016

UVa 12366 - King's Poker

Accepted date: 2016-06-20
Run Time: 0.000
Ranking (as of 2016-06-20): 20 out of 407
Language: C++

/*
  UVa 12366 - King's Poker

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

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

int main()
{
  while (true) {
    int A, B, C;
    scanf("%d %d %d", &A, &B, &C);
    if (!A)
      break;
    // sort A, B, and C in ascending order
    if (A > B)
      swap(A, B);
    if (B > C)
      swap(B, C);
    if (A > B)
      swap(A, B);
    if (A == B && B == C) { // set
      if (A == 13)
        A = 0; // impossible
      else
        A = B = C = ++A;
    }
    else if (A == B) { // pair
      if (C == 13)
        A = 1, B = C = ++B;
      else
        C++;
    }
    else if (B == C) { // pair
      if (A == 12 && B == 13)
        A = B = C = 1;
      else if (A + 1 == B)
        A = C, C = B + 1;
      else
        A++;
    }
    else { // no-pair
      A = B = 1, C = 2;
    }
    if (A)
      printf("%d %d %d\n", A, B, C);
    else
      puts("*");
  }
  return 0;
}

Sunday, June 19, 2016

UVa 10406 - Cutting tabletops

Accepted date: 2016-06-19
Run Time: 0.000
Ranking (as of 2016-06-19): 115 out of 411
Language: C++

/*
  UVa 10406 - Cutting tabletops

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

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

const double epsilon = numeric_limits<float>::epsilon();

struct point {
  double x_, y_;

  point() {}
  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;
  }
};

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

double cross_product(const point& o, const point& a, const point& b)
{
  return (a.x_ - o.x_) * (b.y_ - o.y_) - (b.x_ - o.x_) * (a.y_ - o.y_);
}

void get_cut_points(double d, const point& p, const point& q, point& cp, point& cq)
{
  double x = p.y_ - q.y_, y = q.x_ - p.x_, t = d / euclidean_distance(p, q);
  cp.x_ = p.x_ + x * t; cp.y_ = p.y_ + y * t;
    // cp(p.x_ + d * cos(theta), p.y_ + d * sin(theta)), 
    // cos(theta) = x / distance(p, q), sin(theta) = y / distance(p, q)
  cq.x_ = q.x_ + x * t; cq.y_ = q.y_ + y * t;
}

point get_intersect_points(const point& p1, const point& p2, const point& q1, const point& q2)
{
  double hq1 = cross_product(p1, p2, q1), hq2 = cross_product(p2, p1, q2);
    // fabs(hq1) is the distance between q1 and the vector p1 -> p2,
    // fabs(hq2) is the distance between q2 and the vector p2 -> p1
  double hq = hq1 + hq2;
    return point((q1.x_ * hq2 + q2.x_ * hq1) / hq, (q1.y_ * hq2 + q2.y_ * hq1) / hq);
}

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

#ifdef DEBUG
void print_polygon(int n, const vector<point>& polygon)
{
  for (int i = 0; i < n; i++)
    printf("(%.3lf, %.3lf)%c", polygon[i].x_, polygon[i].y_, ((i < n - 1) ? ' ' : '\n'));
}
#endif

int main()
{
  while (true) {
    double d;
    int n;
    scanf("%lf %d", &d, &n);
    if (d == 0.0 && n == 0)
      break;
    vector<point> points(n);
    for (int i = n - 1; i >= 0; i--)
      scanf("%lf %lf", &points[i].x_, &points[i].y_);
    vector<point> cpoints(n * 2);
    for (int i = 0; i < n; i++)
      get_cut_points(d, points[i], points[(i + 1) % n], cpoints[i * 2], cpoints[i * 2 + 1]);
#ifdef DEBUG
    print_polygon(n * 2, cpoints);
#endif
    for (int i = 0; i < n; i++)
      points[i] = get_intersect_points(cpoints[i * 2], cpoints[i * 2 + 1],
        cpoints[(i * 2 + 2) % (n * 2)], cpoints[(i * 2 + 3) % (n * 2)]);
#ifdef DEBUG
    print_polygon(n, points);
#endif
    printf("%.3lf\n", polygon_area(n, points));
  }
  return 0;
}

Saturday, June 18, 2016

UVa 10574 - Counting Rectangles

Accepted date: 2016-06-18
Run Time: 0.120
Ranking (as of 2016-06-18): 8 out of 412
Language: C++11

/*
  UVa 10574 - Counting Rectangles

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

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

int main()
{
  int t;
  scanf("%d", &t);
  for (int cn = 1; cn <= t; cn++) {
    int n;
    scanf("%d", &n);
    map< int, vector<int> > points;
      // points[i] is the set of y coordinates of points whose x coordinate is i
    for (int i = 0; i < n; i++) {
      int x, y;
      scanf("%d %d", &x, &y);
      pair<map<int, vector<int> >::iterator, bool>
        result = points.insert(make_pair(x, vector<int>()));
      result.first->second.push_back(y);
    }
    for (map<int, vector<int> >::iterator xi = points.begin(); xi != points.end(); ) {
      if (xi->second.size() < 2)
        points.erase(xi++);
      else {
        sort(xi->second.begin(), xi->second.end());
        ++xi;
      }
    }
    long long nr_rectangles = 0;
    for (map<int, vector<int> >::const_iterator xl = points.begin(), xe = points.end();
      xl != xe; ++xl)
      for (map<int, vector<int> >::const_iterator xr = next(xl); xr != xe; ++xr) {
        const vector<int>& yls = xl->second;
        const vector<int>& yrs = xr->second;
        long long nr_ys = 0;
        for (size_t li = 0, le = yls.size(), ri = 0, re = yrs.size();
          li < le && ri < re; ) {
          if (yls[li] < yrs[ri])
            li++;
          else if (yls[li] > yrs[ri])
            ri++;
          else {
            nr_ys++;
            li++, ri++;
          }
        }
        if (nr_ys > 1)
          nr_rectangles += nr_ys * (nr_ys - 1) / 2;
      }
    printf("Case %d: %d\n", cn, nr_rectangles);
  }
  return 0;
}

Thursday, June 16, 2016

UVa 10668 - Expanding Rods

Accepted date: 2016-06-16
Run Time: 0.000
Ranking (as of 2016-06-16): 190 out of 490
Language: C++

/*
  UVa 10668 - Expanding Rods

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

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

int main()
{
  const double pi = 2.0 * acos(0.0), epsilon = numeric_limits<double>::epsilon();
  while (true) {
    double l, n, c;
    scanf("%lf %lf %lf", &l, &n, &c);
    if (l < 0.0 && n < 0.0 && c < 0.0)
      break;
    if (l < epsilon || n < epsilon || c < epsilon) {
      printf("%.3lf\n", 0.0);
      continue;
    }
    double nl = (1.0 + n * c) * l, mid;
    for (double low = 0.0, high = pi / 2.0; low - high < epsilon; ) {
      mid = (low + high) / 2.0;
#ifdef DEBUG
      printf("%.15lf %.15lf %.15lf\n", low, mid, high);
#endif
      double result = nl / mid - l / sin(mid);
      if (result > epsilon)
        low = mid;
      else if (result < -epsilon)
        high = mid;
      else
        break;
    }
    double r = nl / (mid * 2.0), d = r * (1.0 - cos(mid));
    printf("%.3lf\n", d);
  }
  return 0;
}

Tuesday, June 14, 2016

UVa 11374 - Airport Express

Accepted date: 2016-06-14
Run Time: 0.000
Ranking (as of 2016-06-14): 42 out of 412
Language: C++

/*
  UVa 11374 - Airport Express

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

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

const int N_max = 500;

struct edge {
  int v_;
  int w_;
  int commercial_; // 1 for Commercial-Xpress, 0 for Economy-Xpress
  edge(int v, int w, int commercial) : v_(v), w_(w), commercial_(commercial) {}
};

vector<edge> edges[N_max + 1];
bool dvisited[N_max + 1][2];
int distances[N_max + 1][2];
  // distances[i][0/1] is the min. time to vertex i using Commercial-Xpress (1) or not (0)

struct path {
  int u_, commercial_;
} paths[N_max + 1][2];

struct distance_comparator {
  bool operator() (const pair<int, int>& i, const pair<int, int>& j) const
  {
    int di = distances[i.first][i.second], dj = distances[j.first][j.second];
    if (di != dj)
      return di < dj;
    return (i.second != j.second) ? i.second < j.second : i.first < j.first;
  }
};

void print_path(int u, int c, int& cu)
{
  if (paths[u][c].u_ == -1)
    printf("%d", u);
  else {
    if (c && !paths[u][c].commercial_)
      cu = paths[u][c].u_;
    print_path(paths[u][c].u_, paths[u][c].commercial_, cu);
    printf(" %d", u);
  }
}

int main()
{
  int N, S, E;
  bool printed = false;
  while (scanf("%d %d %d", &N, &S, &E) != EOF) {
    if (printed)
      putchar('\n');
    else
      printed = true;
    for (int i = 1; i <= N; i++) {
      edges[i].clear();
      dvisited[i][0] = dvisited[i][1] = false;
      distances[i][0] = distances[i][1] = numeric_limits<int>::max();
    }
    int M;
    scanf("%d", &M);
    while (M--) {
      int X, Y, Z;
      scanf("%d %d %d", &X, &Y, &Z);
      edges[X].push_back(edge(Y, Z, 0));
      edges[Y].push_back(edge(X, Z, 0));
    }
    int K;
    scanf("%d", &K);
    while (K--) {
      int X, Y, Z;
      scanf("%d %d %d", &X, &Y, &Z);
      edges[X].push_back(edge(Y, Z, 1));
      edges[Y].push_back(edge(X, Z, 1));
    }
    // apply the Dijkstra's shortest path algorithm
    set<pair<int, int>, distance_comparator> pq; // priority queue
    distances[S][0] = 0;
    paths[S][0].u_ = -1;
    pq.insert(make_pair(S, 0));
    int min_t, min_c;
    while(!pq.empty()) {
      pair<int, int> p = *pq.begin();
      pq.erase(pq.begin());
      int u = p.first, cc = p.second, t = distances[u][cc];
      dvisited[u][cc] = true;
#ifdef DEBUG
      printf("[%d][%d]: %d\n", u, cc, t);
#endif
      if (u == E) {
        min_t = t, min_c = cc;
        break;
      }
      const vector<edge>& es = edges[u];
      for (size_t i = 0, j = es.size(); i < j; i++) {
        int v = es[i].v_, w = es[i].w_, c = es[i].commercial_;
        if (c) {
          if (!cc && !dvisited[v][1] && t + w < distances[v][1]) {
            pair<int, int> q = make_pair(v, 1);
            pq.erase(q);
            distances[v][1] = t + w, paths[v][1].u_ = u, paths[v][1].commercial_ = cc;
#ifdef DEBUG
            printf("  [%d][1]: %d\n", v, distances[v][1]);
#endif
            pq.insert(q);
          }
        }
        else {
          if (!dvisited[v][cc] && t + w < distances[v][cc]) {
            pair<int, int> q = make_pair(v, cc);
            pq.erase(q);
            distances[v][cc] = t + w, paths[v][cc].u_ = u, paths[v][cc].commercial_ = cc;
#ifdef DEBUG
            printf("  [%d][%d]: %d\n", v, cc, distances[v][cc]);
#endif
            pq.insert(q);
          }
        }
      }
    }
    int cu = -1;
    print_path(E, min_c, cu);
    if (cu != -1)
      printf("\n%d\n", cu);
    else
      printf("\nTicket Not Used\n");
    printf("%d\n", min_t);
  }
  return 0;
}


Sunday, June 12, 2016

UVa 866 - Intersecting Line Segments

Accepted date: 2016-06-12
Run Time: 0.000
Ranking (as of 2016-06-12): 181 out of 631
Language: C++

/*
  UVa 866 - Intersecting Line Segments

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

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

struct point{
  int x, y;
};

struct segment{
  point s, e;
};

inline bool in_range(int l, int u, int n)
{
  return n >= l && n <= u;
}

int direction(const point& p1, const point& p2, const point& p3)
{
  return (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p2.y);
}

bool on_segment(const point& p1, const point& p2, const point& p3)
{
  return in_range(min(p1.x, p2.x), max(p1.x, p2.x), p3.x) &&
    in_range(min(p1.y, p2.y), max(p1.y, p2.y), p3.y);
}

bool segment_intersect(const point& p1, const point& p2, const point& p3, const point& p4)
{
  int d1 = direction(p3, p4, p1), d2 = direction(p3, p4, p2),
    d3 = direction(p1, p2, p3), d4 = direction(p1, p2, p4);
  if((d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0))
    return true;
/*
From the problem descrition:
  It is assumed, as a simplification, 
  that no coincidences may occur between coordinates of singular 
  points (intersections or end points).
*/
/*
  if (d1 == 0 && on_segment(p3, p4, p1))
    return true;
  if (d2 == 0 && on_segment(p3, p4, p2))
    return true;
  if (d3 == 0 && on_segment(p1, p2, p3))
    return true;
  if (d4 == 0 && on_segment(p1, p2, p4))
    return true;
*/
  return false;
}

int main()
{
  int nr_cases;
  scanf("%d", &nr_cases);
  while (nr_cases--) {
    int N;
    scanf("%d", &N);
    vector<segment> segments(N);
    for (int i = 0; i < N; i++)
      scanf("%d %d %d %d",
        &segments[i].s.x, &segments[i].s.y, &segments[i].e.x, &segments[i].e.y);
    int nr_segments = N;
    for (int i = 0; i < N - 1; i++)
      for (int j = i + 1; j < N; j++)
        if (segment_intersect(segments[i].s, segments[i].e, segments[j].s, segments[j].e))
          nr_segments += 2;
    printf("%d\n", nr_segments);
    if (nr_cases)
      putchar('\n');
  }
  return 0;
}

Tuesday, June 7, 2016

UVa 983 - Localized Summing for Blurring

Accepted date: 2016-06-07
Run Time: 0.120
Ranking (as of 2016-06-07): 13 out of 457
Language: C++

/*
  UVa 983 - Localized Summing for Blurring

  To build using Visual Studio 2012:
    cl -EHsc -O2 UVa_983_Localized_Summing_for_Blurring.cpp

  See also UVa 11951 - Area.
*/

#include <cstdio>

const int N_max = 1000;

int sm[N_max][N_max];
  // sm[x][y] is the sum of matrix[i][j] for 0 <= i <= x and 0 <= j <= y

int sum(int xt, int yl, int xb, int yr)
{
  if (xt && yl)
    return sm[xb][yr] - sm[xt - 1][yr] - sm[xb][yl - 1] + sm[xt - 1][yl - 1];
  else if (xt)
    return sm[xb][yr] - sm[xt - 1][yr];
  else if (yl)
    return sm[xb][yr] - sm[xb][yl - 1];
  else
    return sm[xb][yr];
}

int main()
{
  bool printed = false;
  int N, M;
  while (scanf("%d %d", &N, &M) != EOF) {
    if (printed)
      putchar('\n');
    else
      printed = true;
    for (int i = 0; i < N; i++)
      for (int j = 0, s = 0; j < N; j++) {
        int k;
        scanf("%d", &k);
        s += k;
        sm[i][j] = s;
        if (i)
          sm[i][j] += sm[i - 1][j];
      }
    long long s = 0;
    for (int xt = 0; xt < N - M + 1; xt++)
      for (int yl = 0; yl < N - M + 1; yl++) {
        int k = sum(xt, yl, xt + M - 1, yl + M - 1);
        printf("%d\n", k);
        s += k;
      }
    printf("%lld\n", s);
  }
  return 0;
}

Monday, June 6, 2016

UVa 12047 - Highest Paid Toll

Accepted date: 2016-06-06
Run Time: 0.090
Ranking (as of 2016-06-06): 70 out of 419
Language: C++

/*
  UVa 12047 - Highest Paid Toll

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

#include <algorithm>
#include <vector>
#include <set>
#include <queue>
#include <limits>
#include <cstdio>
using namespace std;

const int infinite = numeric_limits<int>::max();
const int N_max = 10000;

struct edge {
  int v_, c_;

  edge() {}
  edge(int v, int c) : v_(v), c_(c) {}
};

vector<edge> edges[N_max + 1], redges[N_max + 1];
int costs[N_max + 1], rcosts[N_max + 1];
bool visited[N_max + 1];

struct cost_comparator {
  int* costs_;
  cost_comparator(int* costs) : costs_(costs) {}
  bool operator() (int i, int j) const {
    if (costs_[i] != costs_[j])
      return costs_[i] < costs_[j];
    else
      return i < j;
  }
};

void dijkstra_shortest_path(int n, int s, const vector<edge>* edges, int* costs)
{
  for (int i = 1; i <= n; i++) {
    visited[i] = false;
    costs[i] = infinite;
  }
  set<int, cost_comparator> pq(costs); // priority queue
  costs[s] = 0.0;
  pq.insert(s);
  while (!pq.empty()) {
    int u = *pq.begin();
    pq.erase(pq.begin());
    visited[u] = true;
    const vector<edge>& es = edges[u];
    for (size_t i = 0, j = es.size(); i < j; i++) {
      const edge& e = es[i];
      if (!visited[e.v_] && costs[e.v_] > costs[u] + e.c_) {
        pq.erase(e.v_); // remove e.v_ if it has already been in the queue
          // this must be done before updating costs[]
        costs[e.v_] = costs[u] + e.c_;
        pq.insert(e.v_);
      }
    }
  }
}

int main()
{
  int T;
  scanf("%d", &T);
  while (T--) {
    int N, M, s, t, p;
    scanf("%d %d %d %d %d", &N, &M, &s, &t, &p);
    for (int i = 1; i <= N; i++) {
      edges[i].clear();
      redges[i].clear();
    }
    while (M--) {
      int u, v, c;
      scanf("%d %d %d", &u, &v, &c);
      edges[u].push_back(edge(v, c));
      redges[v].push_back(edge(u, c));
    }
    dijkstra_shortest_path(N, s, edges, costs);
      // costs[i] is the min. cost from s to i
#ifdef DEBUG
    for (int i = 1; i <= N; i++)
      if (costs[i] < infinite)
        printf("%d: %d ", i, costs[i]);
    putchar('\n');
#endif
    dijkstra_shortest_path(N, t, redges, rcosts);
      // rcosts[i] is the min. cost from t to i traversing the edge reversely
#ifdef DEBUG
    for (int i = 1; i <= N; i++)
      if (rcosts[i] < infinite)
        printf("%d: %d ", i, rcosts[i]);
    putchar('\n');
#endif
    int max_toll = -1;
    queue<int> q;
    for (int i = 1; i <= N; i++)
      visited[i] = false;
    visited[s] = true;
    q.push(s);
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      const vector<edge> es = edges[u];
      for (size_t i = 0, e = es.size(); i < e; i++) {
        int v = es[i].v_;
        if (costs[u] < infinite && rcosts[v] < infinite) {
          int c = costs[u] + es[i].c_ + rcosts[v];
          if (c <= p)
            max_toll = max(max_toll, es[i].c_);
        }
        if (!visited[v]) {
          visited[v] = true;
          q.push(v);
        }
      }
    }
    printf("%d\n", max_toll);
  }
  return 0;
}

Friday, June 3, 2016

UVa 10511 - Councilling

Accepted date: 2016-06-03
Run Time: 0.020
Ranking (as of 2016-06-03): 20 out of 443
Language: C++

/*
  UVa 10511 - Councilling

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

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

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

void add_edge(int u, int v, int c, vector< vector<edge> >& graph)
{
  graph[u].push_back(edge(v, c, c));
  graph[v].push_back(edge(u, c, 0));
}

struct resident {
  string s_;
  int party_;
  vector<int> clubs_;
};

int main()
{
  string line;
  getline(cin, line);
  istringstream iss(line);
  int T;
  iss >> T;
  iss.clear();
  getline(cin, line);
  while (T--) {
    vector<resident> residents;
    map<string, int> parties, clubs;
    while (true) {
      getline(cin, line);
      if (line.empty())
        break;
      iss.str(line);
      residents.push_back(resident());
      resident& r = residents.back();
      iss >> r.s_;
      string s;
      iss >> s;
      parties.insert(make_pair(s, static_cast<int>(parties.size())));
      r.party_ = parties[s];
      while (iss >> s) {
        clubs.insert(make_pair(s, static_cast<int>(clubs.size())));
        r.clubs_.push_back(clubs[s]);
      }
      iss.clear();
    }
    int nr_residents = static_cast<int>(residents.size()),
      nr_clubs = static_cast<int>(clubs.size()),
      nr_parties = static_cast<int>(parties.size());
    int nr_vertices = nr_clubs + nr_residents + nr_parties + 2,
      source = nr_clubs + nr_residents + nr_parties,
      sink = nr_clubs + nr_residents + nr_parties + 1;
    // indices are:
    // 0 - (nr_clubs - 1) : club vertices, 
    // clubs + (nr_clubs + nr_residents - 1): resident vertices,
    // (nr_clubs + nr_residents + nr_parties - 1): party vertices
    vector< vector<edge> > graph(nr_vertices);
    // append the edges from the source to club vertices
    for (int i = 0; i < nr_clubs; i++)
      add_edge(source, i, 1, graph);
    for (int i = 0; i < nr_residents; i++) {
      const resident& r = residents[i];
      // append the edges from the club vertices to the resident vertices
      for (int j = 0, je = static_cast<int>(r.clubs_.size()); j < je; j++)
        add_edge(r.clubs_[j], nr_clubs + i, 1, graph);
      // append the edges from the resident vertices to the party vertices
      add_edge(nr_clubs + i, nr_clubs + nr_residents + r.party_, 1, graph);
    }
    // append the edgs from the party vertices to the sink
    for (int i = 0, c = (nr_clubs - 1) / 2; i < nr_parties; i++)
      add_edge(nr_clubs + nr_residents + i, sink, c, graph);
    netflow(graph, source, sink); // apply Ford-Fulkerson's augmenting path algorithm
    if (total_flow(graph, source) == nr_clubs) {
      vector<string> club_indices(nr_clubs);
      for (map<string, int>::const_iterator ci = clubs.begin(), ce = clubs.end();
        ci != ce; ++ci)
        club_indices[ci->second] = ci->first;
      for (int i = 0; i < nr_clubs; i++) {
        const vector<edge>& edges = graph[i];
        for (int j = 0, je = static_cast<int>(edges.size()); j < je; j++)
          if (edges[j].flow) {
            cout << residents[edges[j].v - nr_clubs].s_ << ' ' << club_indices[i] << endl;
            break;
          }
      }
    }
    else
      puts("Impossible.");
    if (T)
      putchar('\n');
  }
  return 0;
}

Wednesday, June 1, 2016

UVa 10652 - Board Wrapping

Accepted date: 2016-06-01
Run Time: 0.000
Ranking (as of 2016-06-01): 21 out of 490
Language: C++

/*
  UVa 10652 - Board Wrapping

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

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

const double epsilon = numeric_limits<float>::epsilon();
const double pi = 2.0 * acos(0.0);

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

/*
let (x0, y0) be the lower left corner of the rectangle, then:
center point: (x0 + w / 2, y0 + h / 2)
rotate the center point around (x0, y0), by (-a):
(
  x: cos(-a) * (x0 + w / 2 - x0) - sin(-a) * (y0 + h / 2 - y0) + x0
    = cos(a) * w / 2 + sin(a) * h / 2 + x0,
  y: sin(-a) * (x0 + w / 2 - x0) + cos(-a) * (y0 + h / 2 - y0) + y0
    = -sin(a) * w / 2 + cos(a) * h / 2 + y0
)

x0 = x - (cos(a) * w + sin(a) * h) / 2;
y0 = y + (sin(a) * w - cos(a) * h) / 2;

rotate the other 3 points:
  (x0, y0 + h):
    cos(-a) * (x0 - x0) - sin(-a) * (y0 + h - y0) + x0 = sin(a) * h + x0
    sin(-a) * (x0 - x0) + cos(-a) * (y0 + h - y0) + y0 = cos(a) * h + y0

  (x0 + w, y0):
    cos(-a) * (x0 + w - x0) - sin(-a) * (y0 - y0) + x0 = cos(a) * w + x0
    sin(-a) * (x0 + w - x0) + cos(-a) * (y0 - y0) + y0 = -sin(a) * w + y0

  (x0 + w, y0 + h):
    cos(-a) * (x0 + w - x0) - sin(-a) * (y0 + h - y0) + x0 = cos(a) * w + sin(a) * h + x0
    sin(-a) * (x0 + w - x0) + cos(-a) * (y0 + h - y0) + y0 = -sin(a) * w + cos(a) * h + y0

*/

void add_rectangle_points(double x, double y, double w, double h, double a,
  vector<point>& points)
{
  // lower left corner
  double x0 = x - (cos(a) * w + sin(a) * h) / 2, y0 = y + (sin(a) * w - cos(a) * h) / 2;
  points.push_back(point(x0, y0));
  points.push_back(point(sin(a) * h + x0, cos(a) * h + y0));
  points.push_back(point(cos(a) * w + x0, -sin(a) * w + y0));
  points.push_back(point(cos(a) * w + sin(a) * h + x0, -sin(a) * w + cos(a) * h + y0));
}

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

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

int main()
{
  int N;
  scanf("%d", &N);
  while (N--) {
    int n;
    scanf("%d", &n);
    vector<point> points;
    double ra = 0.0;
    for (int i = 0; i < n; i++) {
      double x, y, w, h, phi;
      scanf("%lf %lf %lf %lf %lf", &x, &y, &w, &h, &phi);
      add_rectangle_points(x, y, w, h, phi * pi / 180.0, points);
      ra += w * h;
    }
#ifdef DEBUG
    for (size_t i = 0; i < points.size(); i++)
      printf("%lf %lf\n", points[i].x, points[i].y);
#endif
    vector<point> hull(n * 4);
    convex_hull(points, hull);
#ifdef DEBUG
    for (size_t i = 0; i < hull.size(); i++)
      printf("%lf %lf\n", hull[i].x, hull[i].y);
#endif
    double area = polygon_area(hull);
    printf("%.1lf %%\n", ra * 100.0 / area);
  }
  return 0;
}