Thursday, June 13, 2013

UVa 658 - It's not a Bug, it's a Feature!

Accepted date: 2012-01-28
Ranking (as of 2013-06-13): 61 out of 396
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


/*
  UVa 658 - It's not a Bug, it's a Feature!

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

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

#ifdef  __cplusplus
extern "C" {
#endif

/** priority data type */
typedef int 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 sequence
{
  int time_; // time that has been taken so far in seconds
  int bug_; // bit sets describing the bus
  size_t pqueue_pos_; // used internally by libpqueue

  sequence() : time_(-1), bug_(0), pqueue_pos_(-1) {}
  sequence(int time, int bug) : time_(time), bug_(bug), pqueue_pos_(-1) {}

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

int sequence::get_distance(void* vd)
{
  return reinterpret_cast<sequence*>(vd)->time_;
}

void sequence::set_distance(void* vd, int d)
{
  reinterpret_cast<sequence*>(vd)->time_ = d;
}

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

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

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

/*
  Starting with the state of "+++...+", apply Dijkstra's shortest path algorithm.
  For each state from the queue, see if any available patchs can be applied:
    For a bug of state '+', a patch of '0' or '+'
    For a bug of state '-', a patch of '0' or '-'
*/

struct patch {
  static int n_, mask_;
  int time_; // time in seconds it takes to apply the patch
  int before_present_;
    // bugs that have to be present before the patch can be applied
  int before_absent_;
    // bugs that have to be present before the patch can be applied
  int before_unaffected_;
    // bugs that doesn't matter whether it is present or not
  int after_present_; // bugs that are fixed by the patch
  int after_unaffected_;// bugs that are not affected by the patch

  static void set_mask(int n);
  patch() {}
  patch(int time, const string& before, const string& after);
  int apply(int bug) const;
};

int patch::n_ = 0, patch::mask_ = 0;

void patch::set_mask(int n)
{
  n_ = n; mask_ = (1 << n) - 1;
}

patch::patch(int time, const string& before, const string& after)
  : time_(time), before_present_(0), before_absent_(0), before_unaffected_(0),
  after_present_(0), after_unaffected_(0)
{
  for (int i = 0; i < n_; i++) {
    if (i) {
      before_present_ <<= 1; before_absent_ <<= 1;
      before_unaffected_ <<= 1;
      after_present_ <<= 1; after_unaffected_ <<= 1;
    }
    if (before[i] == '+')
      before_present_ |= 1;
    else if (before[i] == '-')
      before_absent_ |= 1;
    else
      before_unaffected_ |= 1;
    if (after[i] == '+')
      after_present_ |= 1;
    else if (after[i] == '0')
      after_unaffected_ |= 1;
  }
}

int patch::apply(int bug) const
{
  // see if the patch can be applied to bug, and if so, return the applied result
  int b = (bug & before_present_) | (~bug & before_absent_) | before_unaffected_;
  if (b != mask_)
    return -1;
  return after_present_ | (bug & after_unaffected_);
}

int shortest_path(int n, int m, const vector<patch>& patches)
{
  int nr_sequences = 1 << n;
  vector<sequence> sequences(nr_sequences);
    // sequences[i] is the sequence for the bug of i
  vector<bool> queued(nr_sequences, false);
    // queued[i] is true if bug of i has already been queued
  pqueue_t* queue = pqueue_init(nr_sequences,
    sequence::compare_distance, sequence::get_distance,
    sequence::set_distance, sequence::get_position, sequence::set_position);
  int start = patch::mask_;
  for (int i = 0; i < m; i++) {
    int bug = patches[i].apply(start);
    if (bug != -1) {
      sequences[bug] = sequence(patches[i].time_, bug);
      queued[bug] = true;
      pqueue_insert(queue, &sequences[bug]);
    }
  }
  int fixed_time = -1;
  while (pqueue_size(queue)) {
    sequence* s = reinterpret_cast<sequence*>(pqueue_pop(queue));
    s->pqueue_pos_ = -1;
    if (!s->bug_) {
      fixed_time = s->time_; break;
    }
    for (int i = 0; i < m; i++) {
      int bug = patches[i].apply(s->bug_);
      if (bug != -1) {
        int time = s->time_ + patches[i].time_;
        if (queued[bug]) {
          if (sequences[bug].pqueue_pos_ != -1 && sequences[bug].time_ > time)
            pqueue_change_priority(queue, time, &sequences[bug]);
        }
        else {
          sequences[bug] = sequence(time, bug);
          queued[bug] = true;
          pqueue_insert(queue, &sequences[bug]);
        }
      }
    }
  }
  pqueue_free(queue);
  return fixed_time;
}

int main()
{
#ifdef __ELAPSED_TIME__
  clock_t start;
#endif
  for (int pn = 1; ; pn++) {
    int n, m;
    cin >> n >> m;
#ifdef __ELAPSED_TIME__
    if (pn == 1)
      start = clock();
#endif
    if (!n && !m)
      break;
    patch::set_mask(n);
    vector<patch> patches(m);
    for (int i = 0; i < m; i++) {
      int time;
      string before, after;
      cin >> time >> before >> after;
      patches[i] = patch(time, before, after);
    }
    // apply Dijkstra's shortest path algorithm
    int fixed_time = shortest_path(n, m, patches);
    cout << "Product " << pn << endl;
    if (fixed_time != -1)
      cout << "Fastest sequence takes " << fixed_time << " seconds.\n";
    else
      cout << "Bugs cannot be fixed.\n";
    cout << endl;
  }
#ifdef __ELAPSED_TIME__
  cerr << "elapsed time = " <<
    static_cast<double>(clock() - start) / CLOCKS_PER_SEC << " sec.\n";
#endif
  return 0;
}

UVa 10801 - Lift Hopping

Accepted date: 2012-01-29
Ranking (as of 2013-06-13): 239 out of 1168
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


/*
  UVa 10801 - Lift Hopping

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

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <limits>
#include <cstdlib>
using namespace std;

#ifdef  __cplusplus
extern "C" {
#endif

/** priority data type */
typedef int 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 edge {
  int v; // destination vertex
  int weight; // waiting time or travelling time

  edge() : v(-1), weight(-1) {}
  edge(int _v, int _weight) : v(_v), weight(_weight) {}
};

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

  vertex_distance() : v(-1), distance(-1), pqueue_pos(-1) {}
  vertex_distance(int _v, int _distance)
    : v(_v), distance(_distance), pqueue_pos(-1) {}

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

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

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

int vertex_distance::compare_distance(int next, int 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;
}

bool shortest_path(int nr_vertices, int start, int end,
  const vector< vector<edge> >& edges,
  vector<vertex_distance>& distances, vector<int>& parent_vertices)
{
  for (int i = 0; i < nr_vertices; i++)
    distances[i] = vertex_distance(i, ((i != start) ?
      numeric_limits<int>::max() : 0));
  // queue items (vertex_distance instances) are arranged in ascending order of 
  // their distances from the start vertex
  pqueue_t* queue = pqueue_init(distances.size(),
    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 < nr_vertices; i++)
    pqueue_insert(queue, &distances[i]);
  bool successful = false;
  while (pqueue_size(queue)) {
    vertex_distance* vd = reinterpret_cast<vertex_distance*>(pqueue_pop(queue));
    vd->pqueue_pos = -1;
    int u = vd->v;
    if (u == end) {
      successful = true; break;
    }
    int d = distances[u].distance;
    if (d == numeric_limits<int>::max())
      break;
    for (size_t i = 0; i < edges[u].size(); i++) {
      const edge& e = edges[u][i];
      if (distances[e.v].pqueue_pos != -1
        // an vertex_distance instance for t.route is still in queue
        && d + e.weight < distances[e.v].distance) {
        parent_vertices[e.v] = u;
        pqueue_change_priority(queue, d + e.weight, &distances[e.v]);
      }
    }
  }
  return successful;
}

int main()
{
  const int nr_floors = 100, s_wait = 60;
  string line;
  istringstream iss;
  while (getline(cin, line)) {
    iss.str(line);
    int n, k;
    iss >> n >> k;
    iss.clear();
    getline(cin, line);
    iss.str(line);
    vector<int> speeds(n);
    for (int i = 0; i < n; i++)
      iss >> speeds[i];
    iss.clear();
    vector< vector<edge> > edges(nr_floors);
      // edges[i] is the vector of edges from the i-th vertex
    for (int i = 0; i < n; i++) {
      getline(cin, line);
      iss.str(line);
      vector<int> floors(nr_floors);
      int j = 0;
      while (iss >> floors[j])
        j++;
      for (int fi = 0; fi < j - 1; fi++) {
        int fli = floors[fi];
        for (int fj = fi + 1; fj < j; fj++) {
          int flj = floors[fj];
          int s = speeds[i] * abs(flj - fli) + s_wait;
          edges[fli].push_back(edge(flj, s));
          edges[flj].push_back(edge(fli, s));
        }
      }
      iss.clear();
    }
    vector<vertex_distance> distances(nr_floors);
    vector<int> parent_vertices(nr_floors);
    // apply Dijkstra's shortest path algorithm
    bool successful =
      shortest_path(nr_floors, 0, k, edges, distances, parent_vertices);
    if (successful)
      cout << ((k) ? distances[k].distance - s_wait : 0) << endl;
    else
      cout << "IMPOSSIBLE\n";
  }
  return 0;
}

UVa 558 - Wormholes

Accepted date: 2012-02-01
Ranking (as of 2013-06-13): 639 out of 2762
Language: C++

/*
  558 - Wormholes

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

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

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

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

bool bellman_ford(int n, int source, const vector<edge>& edges)
{
  // initialize the graph
  vector<int> distances(n, numeric_limits<int>::max());
  distances[source] = 0;
  // relax the edges repeatedly
  for (int i = 0; i < n - 1; i++)
    for (size_t j = 0, je = edges.size(); j < je; j++) {
      const edge& e = edges[j];
      if (distances[e.u_] + e.weight_ < distances[e.v_])
        distances[e.v_] = distances[e.u_] + e.weight_;
    }
  // check for negative-weight cycles
  for (size_t i = 0, ie = edges.size(); i < ie; i++) {
    const edge& e = edges[i];
    if (distances[e.u_] + e.weight_ < distances[e.v_])
      return true; // the graph contains a negative-weight cycle
  }
  return false;
}

int main()
{
  int c;
  cin >> c;
  while (c--) {
    int n, m;
    cin >> n >> m;
    vector<edge> edges(m);
    for (int i = 0; i < m; i++)
      cin >> edges[i].u_ >> edges[i].v_ >> edges[i].weight_;
    cout << ((bellman_ford(n, 0, edges)) ? "possible\n" : "not possible\n");
  }
  return 0;
}

UVa 515 - King

Accepted date: 2012-02-04
Ranking (as of 2013-06-13): 172 out of 348
Language: C++

/*
  UVa 515 - King

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

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

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

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

bool bellman_ford(int n, int source, const vector<edge>& edges)
{
  // initialize the graph
  vector<int> distances(n, numeric_limits<int>::max());
  distances[source] = 0;
  // relax the edges repeatedly
  for (int i = 0; i < n - 1; i++)
    for (size_t j = 0, je = edges.size(); j < je; j++) {
      const edge& e = edges[j];
      if (distances[e.u_] + e.weight_ < distances[e.v_])
        distances[e.v_] = distances[e.u_] + e.weight_;
    }
  // check for negative-weight cycles
  for (size_t i = 0, ie = edges.size(); i < ie; i++) {
    const edge& e = edges[i];
    if (distances[e.u_] + e.weight_ < distances[e.v_])
      return true; // the graph contains a negative-weight cycle
  }
  return false;
}

int main()
{
  while (true) {
    int n;
    cin >> n;
    if (!n)
      break;
    int m;
    cin >> m;
    vector<edge> edges(n + m + 1);
    int i;
    for (i = 0; i < n + 1; i++)
      edges[i] = edge(n + 1, i, 0);
        // edges from specical vertex (n + 1) to any other vertex
    for ( ; i < n + m + 1; i++) {
      int j, k, c;
      string op;
      cin >> j >> k >> op >> c;
      k += j; j--;
      if (op == "gt") {
        swap(j, k);
        c++; c = -c;
      }
      else
        c--;
      edges[i] = edge(j, k, c);
    }
    // Bellman-Ford's shortest path algorithm should start 
    // from the special vertex (n + 1)
    cout << ((bellman_ford(n + 2, n + 1, edges)) ?
      "successful conspiracy\n" : "lamentable kingdom\n");
  }
  return 0;
}

Sunday, June 9, 2013

UVa 104 - Arbitrage

Accepted date: 2012-02-09
Ranking (as of 2013-06-09): 1087 out of 3240
Language: C++

/*
  UVa 104 - Arbitrage

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

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

void all_pairs_shortest_path(int n, const vector< vector<double> >& weights,
  vector< vector< vector<double> > >& distances,
  vector <vector< vector<int> > >& nexts)
{
  for (int u = 0; u < n; u++)
    for (int v = 0; v < n; v++)
      distances[u][v][0] = weights[u][v];
  for (int k = 1; k < n; k++)
    for (int u = 0; u < n; u++)
      for (int v = 0; v < n; v++) {
        distances[u][v][k] = numeric_limits<float>::max();
        for (int x = 0; x < n; x++) {
          double through_x = distances[u][x][k - 1] + weights[x][v];
          if (through_x < distances[u][v][k]) {
            distances[u][v][k] = through_x; nexts[u][v][k] = x;
          }
        }
      }
}

void print_path(int u, int v, int k,
  const vector <vector< vector<int> > >& nexts)
{
  int x = nexts[u][v][k];
  if (k) {
    print_path(u, x, k - 1, nexts);
    cout << ' ' << v + 1;
  }
  else
    cout << u + 1 << ' ' << v + 1;
}

bool print_arbitrage(int n, const vector< vector< vector<double> > >& distances,
  const vector <vector< vector<int> > >& nexts)
{
  for (int k = 0; k < n; k++)
    for (int u = 0; u < n; u++) {
      double profit = 1.0 / exp(distances[u][u][k]);
      if (profit > 1.01) {
        print_path(u, u, k, nexts);
        cout << endl;
        return true;
      }
    }
  return false;
}

int main()
{
  int n;
  while (cin >> n) {
    vector< vector<double> > weights(n, vector<double>(n));
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (i == j)
          weights[i][j] = 0.0; // log(1.0)
        else {
          double r;
          cin >> r;
          weights[i][j] = -log(r);
        }
    vector< vector< vector<double> > >
      distances(n, vector< vector<double> >(n, vector<double>(n)));
      // distance[u][v][k] is the shortest path from u to v that passes 
      // at most (k + 1) edges
    vector <vector< vector<int> > >
      nexts(n, vector< vector<int> >(n, vector<int>(n, -1)));
    all_pairs_shortest_path(n, weights, distances, nexts);
    if (!print_arbitrage(n, distances, nexts))
      cout << "no arbitrage sequence exists\n";
  }
  return 0;
}

UVa 488 - Triangle Wave

Accepted date: 2012-02-11
Ranking (as of 2013-06-09): 460 out of 8889
Language: C++

/*
  UVa 488 - Triangle Wave

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

#include <iostream>
using namespace std;

const char* waves[] = {
  "",
  "1\n",
  "1\n22\n1\n",
  "1\n22\n333\n22\n1\n",
  "1\n22\n333\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n88888888\n7777777\n666666\n55555\n4444\n333\n22\n1\n",
  "1\n22\n333\n4444\n55555\n666666\n7777777\n88888888\n999999999\n88888888\n7777777\n666666\n55555\n4444\n333\n22\n1\n"
};

int main()
{
  int nr_cases;
  cin >> nr_cases;
  while (nr_cases--) {
    int amplitude, frequency;
    cin >> amplitude >> frequency;
    if (amplitude < 0)
      amplitude = 0;
    const char* w = waves[amplitude];
    for (int f = 0; f < frequency; f++) {
      if (f)
        cout << endl;
      cout << w;
    }
    if (nr_cases)
      cout << endl;
        // outputs of two consecutive cases will be separated by a blank line
  }
  return 0;
}

UVa 10878 - Decode the tape

Accepted date: 2012-02-13
Ranking (as of 2013-06-09): 655 out of 3135
Language: C++

/*
  UVa 10878 - Decode the tape

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

#include <cstdio>

int main()
{
  const int nr_chrs = 16;
  char line[nr_chrs];
  while (gets(line)) {
    if (line[0] != '|') {
      continue;
    }
    char c = 0;
    for (int i = 1; i < 10; i++) {
      if (i > 1 && line[i] != '.')
        c <<= 1;
      if (line[i] == 'o')
        c |= 1;
    }
    putchar(c);
  }
  return 0;
}