Saturday, June 15, 2013

UVa 10759 - Dice Throwing

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

/*
  UVa 10759 - Dice Throwing

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

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

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

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

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

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

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

UVa 10277 - Boastin' Red Socks

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

/*
  UVa 10277 - Boastin' Red Socks

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

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

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

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

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

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

UVa 10169 - Urn-ball Probabilities !

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

/*
  UVa 10169 - Urn-ball Probabilities !

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

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

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

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

UVa 11181 - Probability|Given

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

/*
  UVa 11181 - Probability|Given

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

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

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

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

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

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

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

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

UVa 557 - Burger

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

/*
  UVa 557 - Burger

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

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

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

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

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

UVa 10397 - Connect the Campus

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

The priority queue implementation (the functions prefixed with "pqueue" and their associated definitions, etc. that are surrounded by the below 'extern "C"' block) is based on the code from https://github.com/vy/libpqueue and is licensed under the Apache 2.0 license:
  Copyright 2010 Volkan Yazici
  Copyright 2006-2010 The Apache Software Foundation


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

<pre class="prettyprint">

/*
  UVa 10397 - Connect the Campus

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

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

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

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

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

#ifdef  __cplusplus
extern "C" {
#endif

/** priority data type */
typedef double pqueue_pri_t;

/** callback functions to get/set/compare the priority of an element */
typedef pqueue_pri_t (*pqueue_get_pri_f)(void *a);
typedef void (*pqueue_set_pri_f)(void *a, pqueue_pri_t pri);
typedef int (*pqueue_cmp_pri_f)(pqueue_pri_t next, pqueue_pri_t curr);

/** callback functions to get/set the position of an element */
typedef size_t (*pqueue_get_pos_f)(void *a);
typedef void (*pqueue_set_pos_f)(void *a, size_t pos);

/** debug callback function to print a entry */
typedef void (*pqueue_print_entry_f)(FILE *out, void *a);

/** the priority queue handle */
typedef struct pqueue_t
{
    size_t size;
    size_t avail;
    size_t step;
    pqueue_cmp_pri_f cmppri;
    pqueue_get_pri_f getpri;
    pqueue_set_pri_f setpri;
    pqueue_get_pos_f getpos;
    pqueue_set_pos_f setpos;
    void **d;
} pqueue_t;

#define left(i)   ((i) << 1)
#define right(i)  (((i) << 1) + 1)
#define parent(i) ((i) >> 1)

pqueue_t *
pqueue_init(size_t n,
            pqueue_cmp_pri_f cmppri,
            pqueue_get_pri_f getpri,
            pqueue_set_pri_f setpri,
            pqueue_get_pos_f getpos,
            pqueue_set_pos_f setpos)
{
    pqueue_t *q;

    if (!(q = (pqueue_t *)malloc(sizeof(pqueue_t))))
        return NULL;

    /* Need to allocate n+1 elements since element 0 isn't used. */
    if (!(q->d = (void **)(malloc((n + 1) * sizeof(void *))))) {
        free(q);
        return NULL;
    }

    q->size = 1;
    q->avail = q->step = (n+1);  /* see comment above about n+1 */
    q->cmppri = cmppri;
    q->setpri = setpri;
    q->getpri = getpri;
    q->getpos = getpos;
    q->setpos = setpos;

    return q;
}

void
pqueue_free(pqueue_t *q)
{
    free(q->d);
    free(q);
}

size_t
pqueue_size(pqueue_t *q)
{
    /* queue element 0 exists but doesn't count since it isn't used. */
    return (q->size - 1);
}

static void
bubble_up(pqueue_t *q, size_t i)
{
    size_t parent_node;
    void *moving_node = q->d[i];
    pqueue_pri_t moving_pri = q->getpri(moving_node);

    for (parent_node = parent(i);
         ((i > 1) && q->cmppri(q->getpri(q->d[parent_node]), moving_pri));
         i = parent_node, parent_node = parent(i))
    {
        q->d[i] = q->d[parent_node];
        q->setpos(q->d[i], i);
    }

    q->d[i] = moving_node;
    q->setpos(moving_node, i);
}

static size_t
maxchild(pqueue_t *q, size_t i)
{
    size_t child_node = left(i);

    if (child_node >= q->size)
        return 0;

    if ((child_node+1) < q->size &&
        q->cmppri(q->getpri(q->d[child_node]), q->getpri(q->d[child_node+1])))
        child_node++; /* use right child instead of left */

    return child_node;
}

static void
percolate_down(pqueue_t *q, size_t i)
{
    size_t child_node;
    void *moving_node = q->d[i];
    pqueue_pri_t moving_pri = q->getpri(moving_node);

    while ((child_node = maxchild(q, i)) &&
           q->cmppri(moving_pri, q->getpri(q->d[child_node])))
    {
        q->d[i] = q->d[child_node];
        q->setpos(q->d[i], i);
        i = child_node;
    }

    q->d[i] = moving_node;
    q->setpos(moving_node, i);
}

int
pqueue_insert(pqueue_t *q, void *d)
{
    void *tmp;
    size_t i;
    size_t newsize;

    if (!q) return 1;

    /* allocate more memory if necessary */
    if (q->size >= q->avail) {
        newsize = q->size + q->step;
        if (!(tmp = realloc(q->d, sizeof(void *) * newsize)))
            return 1;
        q->d = (void **)tmp;
        q->avail = newsize;
    }

    /* insert item */
    i = q->size++;
    q->d[i] = d;
    bubble_up(q, i);

    return 0;
}

void
pqueue_change_priority(pqueue_t *q,
                       pqueue_pri_t new_pri,
                       void *d)
{
    size_t posn;
    pqueue_pri_t old_pri = q->getpri(d);

    q->setpri(d, new_pri);
    posn = q->getpos(d);
    if (q->cmppri(old_pri, new_pri))
        bubble_up(q, posn);
    else
        percolate_down(q, posn);
}

void *
pqueue_pop(pqueue_t *q)
{
    void *head;

    if (!q || q->size == 1)
        return NULL;

    head = q->d[1];
    q->d[1] = q->d[--q->size];
    percolate_down(q, 1);

    return head;
}

#ifdef  __cplusplus
}
#endif

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

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

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

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

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

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

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

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

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


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

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

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

</pre>

UVa 10369 - Arctic Network

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

/*
  UVa 10369 - Arctic Network

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

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

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

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

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

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

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

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

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

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