Saturday, June 28, 2014

UVa 10475 - Help the Leaders

Accepted date: 2014-06-28
Ranking (as of 2014-06-28): 43 out of 302
Language: C++

/*
  UVa 10475 - Help the Leaders

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

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

const int t_max = 16, nr_chars_max = 15;

struct topic {
  int length_;
  char s_[nr_chars_max + 1];
  topic() : length_(0) {}
  topic(const char* s)
    : length_(strlen(s))
  {
    transform(s, s + length_, s_, (int(*)(int))toupper);
    s_[length_] = '\0';
  }
} topics[t_max];

int compare_topic(const void* i, const void* j)
{
  const topic *ti = reinterpret_cast<const topic*>(i),
    *tj = reinterpret_cast<const topic*>(j);
  return (ti->length_ != tj->length_) ?
    tj->length_ - ti->length_ : strcmp(ti->s_, tj->s_);
}

bool prohibited_pairs[t_max][t_max];

void help_leader(int t, int s, int ti, int si, int group[])
{
  if (si == s) {
    for (int i = 0; i < s; i++)
      printf("%s%c", topics[group[i]].s_, (i < s - 1) ? ' ' : '\n');
  }
  else if (t - ti > s - si) {
    for (int i = ti + 1; i < t; i++) {
      int j;
      for (j = 0; j < si; j++)
        if (prohibited_pairs[i][group[j]])
          break;
      if (j == si) {
        group[si] = i;
        help_leader(t, s, i, si + 1, group);
      }
    }
  }
}

int main()
{
  int n;
  scanf("%d", &n);
  for (int sn = 1; sn <= n; sn++) {
    int t, p, s;
    scanf("%d %d %d", &t, &p, &s);
    for (int i = 0; i < t; i++) {
      scanf("%s", topics[i].s_);
      topics[i] = topics[i].s_;
    }
    qsort(topics, t, sizeof(topic), compare_topic);
    for (int i = 0; i < t; i++)
      for (int j = 0; j < t; j++)
        prohibited_pairs[i][j] = false;
    for (int i = 0; i < p; i++) {
      topic ti, tj;
      scanf("%s %s", ti.s_, tj.s_);
      ti = ti.s_; tj = tj.s_;
      int pi = reinterpret_cast<topic*>(
        bsearch(&ti, topics, t, sizeof(topic), compare_topic)) - topics,
        pj = reinterpret_cast<topic*>(
          bsearch(&tj, topics, t, sizeof(topic), compare_topic)) - topics;
      prohibited_pairs[pi][pj] = prohibited_pairs[pj][pi] = true;
    }
    printf("Set %d:\n", sn);
    for (int i = 0; i < t - s + 1; i++) {
      int group[t_max]; // array of topic indices
      group[0] = i;
      help_leader(t, s, i, 1, group);
    }
    putchar('\n');
  }
  return 0;
}

UVa 10460 - Find the Permuted String

Accepted date: 2014-06-27
Ranking (as of 2014-06-28): 450 out of 524
Language: C++

/*
  UVa 10460 - Find the Permuted String

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

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

int main()
{
  int t;
  cin >> t;
  while (t--) {
    string s;
    cin >> s;
    int i;
    cin >> i;
    i--;
    int n = static_cast<int>(s.length());
    vector<int> indices(n);
    for (int j = n; j; j--) {
      indices[j - 1] = i % j;
      i /= j;
    }
    vector<char> ps;
    for (int j = 0; j < n; j++)
      ps.insert(ps.begin() + indices[j], s[j]);
    for (int i = 0; i < n; i++)
      cout << ps[i];
    cout << endl;
  }
  return 0;
}

Wednesday, June 25, 2014

UVa 487 - Boggle Blitz

Accepted date: 2014-06-25
Ranking (as of 2014-06-25): 98 out of 352
Language: C++

/*
  UVa 487 - Boggle Blitz

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

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

const int n_max = 20, nr_dirs = 8;
const int dirs[nr_dirs][2] = {
  {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}
};
char table[n_max][n_max + 1];

struct word {
  int i_, j_;
  int length_;
  char s_[n_max * n_max + 1];
  word() : i_(-1), j_(-1), length_(0) {}
  word(int i, int j) : i_(i), j_(j), length_(0) {}
  word(const word& w) : i_(w.i_), j_(w.j_), length_(w.length_)
    {memcpy(s_, w.s_, w.length_);}
  word& operator=(const word& w)
    {i_ = w.i_; j_ = w.j_; length_ = w.length_; memcpy(s_, w.s_, w.length_);
    return *this;}

  void push_back(char c) {s_[length_++] = c;}

  bool operator<(const word& w) const {
    return (length_ != w.length_) ? length_ < w.length_ : strcmp(s_, w.s_) < 0;}
};

set<word> words;

void bfs(int n, int si, int sj)
{
  word sw(si, sj);
  sw.push_back(table[si][sj]);
  queue<word> wq;
  wq.push(sw);
  while (!wq.empty()) {
    word w = wq.front(); wq.pop();
    if (w.length_ >= 3) {
      word nw(w);
      nw.push_back('\0');
      words.insert(nw);
    }
    for (int k = 0; k < nr_dirs; k++) {
      int i = w.i_ + dirs[k][0], j = w.j_ + dirs[k][1];
      if (i >= 0 && i < n && j >= 0 && j < n &&
        w.s_[w.length_ - 1] < table[i][j]) {
        word nw(w);
        nw.i_ = i; nw.j_ = j;
        nw.push_back(table[i][j]);
        wq.push(nw);
      }
    }
  }
}

int main()
{
  int nc;
  scanf("%d", &nc);
  while (nc--) {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
      scanf("%s", table[i]);
    words.clear();
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        bfs(n, i, j);
    for (set<word>::const_iterator i = words.begin(), e = words.end();
      i != e; ++i)
      printf("%s\n", i->s_);
    if (nc)
      putchar('\n');
  }
  return 0;
}

Tuesday, June 24, 2014

UVa 380 - Call Forwarding

Accepted date: 2014-06-24
Ranking (as of 2014-06-24): 369 out of 547
Language: C++

/*
  UVa 380 - Call Forwarding

  To build using Visucal Studio 2012:
    cl -EHsc UVa_380_Call_Forwarding.cpp
*/

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

struct call_forwarding {
  int t_; // target
  int st_, et_; // start time, end time

  call_forwarding(int t, int st, int et) : t_(t), st_(st), et_(et) {}
  bool operator<(const call_forwarding& cf) const {return st_ < cf.st_;}
};

struct request {
  bool f_; // true if forwarded
  vector<call_forwarding> forwardings_;
  request() : f_(false) {}
};

int call_forward(int t, int s, map<int, request>& requests)
{
  for (map<int, request>::iterator i = requests.begin(), e = requests.end();
    i != e; ++i)
    i->second.f_ = false;
  while (true) {
    map<int, request>::iterator i = requests.find(s);
    if (i == requests.end()) // forwarding is not registered
      return s;
    else if (i->second.f_) // already has been forwarded
      return 9999;
    else {
      i->second.f_ = true;
      s = -1;
      for (vector<call_forwarding>::const_iterator
        j = i->second.forwardings_.begin(), e = i->second.forwardings_.end();
        j != e; ++j)
        if (t >= j->st_ && t <= j->et_) {
          s = j->t_; break;
        }
      if (s == -1)
        return i->first;
    }
  }
}

int main()
{
  cout << "CALL FORWARDING OUTPUT\n";
  int nr_systems;
  cin >> nr_systems;
  for (int ns = 1; ns <= nr_systems; ns++) {
    map<int, request> requests;
    while (true) {
      int s, t, st, d;
      cin >> s;
      if (!s)
        break;
      cin >> st >> d >> t;
      pair<map<int, request>::iterator, bool> result =
        requests.insert(make_pair(s, request()));
      result.first->second.forwardings_.push_back(
        call_forwarding(t, st, st + d));
    }
    cout << "SYSTEM " << ns << endl;
    while (true) {
      int t, s;
      cin >> t;
      if (t == 9000)
        break;
      cin >> s;
      cout << "AT " << setfill('0') << setw(4) <<
        t << " CALL TO " << setw(4) << s << " RINGS " <<
        setw(4) << call_forward(t, s, requests) << endl;
    }
  }
  cout << "END OF OUTPUT\n";
  return 0;
}

Sunday, June 22, 2014

UVa 10576 - Y2K Accounting Bug

Accepted date: 2014-06-22
Ranking (as of 2014-06-22): 220 out of 482
Language: C++

/*
  UVa 10576 - Y2K Accounting Bug

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

#include <cstdio>

const int nr_months = 12, nr_posts = 8, nr_consecutive_posts = 5;
int s, d, max_amount, posts[nr_months];

void calculate_amount(int pi, int amount)
{
  if (pi == nr_posts) {
    amount = 0;
    for (int i = 0; i < nr_months; i++) {
#ifdef DEBUG
      printf("%d%c", posts[i], ((i < nr_months - 1) ? ' ' : '\n'));
#endif
      amount += posts[i];
    }
    if (amount > max_amount)
      max_amount = amount;
  }
  else if (!pi) {
    int i;
    for (i = 0; i < nr_consecutive_posts; i++) {
      posts[i] = s;
      amount += s;
    }
    for (i--; i >= 0 && amount >= 0; i--) {
      posts[i] = -d;
      amount -= s + d;
    }
    calculate_amount(pi + 1, amount);
  }
  else {
    amount -= posts[pi - 1];
    posts[pi + nr_consecutive_posts - 1] = (amount + s < 0) ? s : -d;
    amount += posts[pi + nr_consecutive_posts - 1];
    calculate_amount(pi + 1, amount);
  }
}

int main()
{
  while (scanf("%d %d", &s, &d) != EOF) {
    max_amount = -1;
    calculate_amount(0, 0);
    if (max_amount >= 0)
      printf("%d\n", max_amount);
    else
      puts("Deficit");
  }
  return 0;
}

UVa 670 - The dog task

Accepted date: 2014-06-21
Ranking (as of 2014-06-22): 274 out of 668
Language: C++

/*
  UVa 670 - The dog task

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

#include <iostream>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
#include <cmath>
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;
}

struct point {
  int x_, y_;
};

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

int main()
{
  int l;
  cin >> l;
  while (l--) {
    int n, m;
    cin >> n >> m;
    vector<point> routes(n), places(m);
    for (int i = 0; i < n; i++)
      cin >> routes[i].x_ >> routes[i].y_;
    vector<double> route_distances(n - 1);
    for (int i = 0; i < n - 1; i++)
      route_distances[i] = euclidean_distance(routes[i], routes[i + 1]);
    for (int i = 0; i < m; i++)
      cin >> places[i].x_ >> places[i].y_;

    int nr_vertices = n + m + 2;
    vector< vector<edge> > graph(nr_vertices);
    // indices are:
    // 0 - (m - 1): Ralph's interesting place vertices
    // m - (m + n - 1) : Bob's route vertices, 
    //  i-th vertex represents the path from (x(i), y(i)) to (x(i + 1), y(i + 1))
    // n + m: source vertex, n + m + 1: sink vertex
    int source = n + m, sink = n + m + 1;
    for (int i = 0; i < m; i++) {
      // append the edges between the source and place vertices
      graph[source].push_back(edge(i, 1, 1));
      graph[i].push_back(edge(source, 1, 0));
      for (int j = 0; j < n - 1; j++) {
        // append the edges between place vertices and route vertices
        if (euclidean_distance(places[i], routes[j]) +
          euclidean_distance(places[i], routes[j + 1]) <=
          2.0 * route_distances[j]) {
          graph[i].push_back(edge(m + j, 1, 1));
          graph[m + j].push_back(edge(i, 1, 0));
        }
      }
    }
    for (int i = m; i < m + n; i++) {
      // append the edges between route vertices and the sink
      graph[i].push_back(edge(sink, 1, 1));
      graph[sink].push_back(edge(i, 1, 0));
    }
    netflow(graph, source, sink);
      // apply Ford-Fulkerson's augmenting path algorithm
    cout << n + total_flow(graph, source) << endl;
    for (int i = 0; i < n - 1; i++) {
      if (i)
        cout << ' ';
      cout << routes[i].x_ << ' ' << routes[i].y_;
      const vector<edge>& edges = graph[m + i];
      int j = -1;
      for (size_t k = 0; k < edges.size(); k++)
        if (edges[k].residual && edges[k].v < m) {
          j = edges[k].v; break;
        }
      if (j != -1)
        cout << ' ' << places[j].x_ <<
          ' ' << places[j].y_;
    }
    cout << ' ' << routes[n - 1].x_ <<
      ' ' << routes[n - 1].y_ << endl;
    if (l)
      cout << endl;
  }
  return 0;
}

Saturday, June 21, 2014

UVa 753 - A Plug for UNIX

Accepted date: 2014-06-21
Ranking (as of 2014-06-21): 137 out of 715
Language: C++

/*
  UVa 753 - A Plug for UNIX

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

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>
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;
}

int register_name(const string& s, map<string, int>& names)
{
  map<string, int>::iterator i = names.find(s);
  if (i != names.end())
    return i->second;
  else {
    int n = static_cast<int>(names.size());
    names[s] = n;
    return n;
  }
}

void enumerate_plugs(vector<int>& d, int max_rpi,
  const multimap<int, int>& adapters)
{
  vector<bool> visited(max_rpi, false);
  queue<int> q;
  visited[d[0]] = true;
  q.push(d[0]);
  while (!q.empty()) {
    int r = q.front();
    q.pop();
    pair< map<int, int>::const_iterator,
      map<int, int>::const_iterator > result =
      adapters.equal_range(r);
    for (map<int, int>::const_iterator i = result.first;
      i != result.second; ++i) {
      if (!visited[i->second]) {
        d.push_back(i->second);
        visited[i->second] = true;
        q.push(i->second);
      }
    }
  }
}

int main()
{
  int nr_cases;
  cin >> nr_cases;
  while (nr_cases--) {
    map<string, int> names;
      // keys are plug names, values are their corresponding #s
    int n;
    cin >> n;
    vector<int> receptacles(n); // receptacles[i] is the # of plug
    for (int i = 0; i < n; i++) {
      string s;
      cin >> s;
      receptacles[i] = register_name(s, names);
    }
    int m;
    cin >> m; 
    vector< vector<int> > devices(m);
      // devices[i] is the vector of #s of plugs
      // that can be connected directly or indirectly 
      // though one ore more adapters
    for (int i = 0; i < m; i++) {
      string s;
      cin >> s >> s; // device names are discarded
      devices[i].push_back(register_name(s, names));
    }
    int k;
    cin >> k;
    multimap<int, int> adapters;
      // keys are receptacle #s, values are plug #s
    int max_rpi = -1;
    for (int i = 0; i < k; i++) {
      string s, t;
      cin >> s >> t;
      int ri = register_name(s, names), pi = register_name(t, names);
      max_rpi = max(max_rpi, max(ri, pi));
      adapters.insert(make_pair(ri, pi));
    }
    // for each device, enumerate the plugs that can be connected to
    for (int i = 0; i < m; i++)
      enumerate_plugs(devices[i], max_rpi, adapters);

    int nr_vertices = n + m + 2;
    vector< vector<edge> > graph(nr_vertices);
    // indices are:
    //  0 - (n - 1): receptacles vertices, n - (n + m - 1): device vertices,
    //  (n + m): source vertex, (n + m + 1): sink vertex
    int source = n + m, sink = n + m + 1;
    for (int i = 0; i < m; i++) {
      // append the edges between the source and device vertices
      graph[source].push_back(edge(i + n, 1, 1));
      graph[i + n].push_back(edge(source, 1, 0));
      for (size_t j = 0; j < devices[i].size(); j++) {
        int pi = devices[i][j];
        // append the edges between device vertices and receptacle vertices
        for (int ri = 0; ri < n; ri++)
          if (receptacles[ri] == pi) {
            graph[i + n].push_back(edge(ri, 1, 1));
            graph[ri].push_back(edge(i + n, 1, 0));
          }
      }
    }
    for (int i = 0; i < n; i++) {
      // append the edges between receptacle vertices and the sink
      graph[i].push_back(edge(sink, 1, 1));
      graph[sink].push_back(edge(i, 1, 0));
    }
    netflow(graph, source, sink);
      // apply Ford-Fulkerson's augmenting path algorithm
    cout << m - total_flow(graph, source) << endl;

    if (nr_cases)
      cout << endl;
  }
  return 0;
}

Wednesday, June 18, 2014

UVa 11733 - Airports

Accepted date: 2014-06-17
Ranking (as of 2014-06-18): 69 out of 874
Language: C++

/*
  UVa 11733 - Airports

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

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

const int n_max = 10000, m_max = 100000;
class union_find {
public:
  void init(int n);
  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
  int representatives_[n_max];
    // representatives[i] is the representative of a set to which i belongs
  int ranks_[n_max];
    // ranks_[i] is the number of elements in the set to which i belongs
} vertices;

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

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_, weight_;
  bool operator<(const edge& e) const {return weight_ < e.weight_;}
} edges[m_max];

int main()
{
  int t;
  scanf("%d", &t);
  for (int tc = 1; tc <= t; tc++) {
    int n, m, a;
    scanf("%d %d %d", &n, &m, &a);
    for (int i = 0; i < m; i++) {
      int x, y, c;
      scanf("%d %d %d", &edges[i].u_, &edges[i].v_, &edges[i].weight_);
      edges[i].u_--; edges[i].v_--;
    }
    // apply Kruskal's minimum spanning tree algorithm
    vertices.init(n);
    sort(edges, edges + m); // sort the edges in ascending order of their weights
    int cost = 0;
    for (int i = 0; i < m && edges[i].weight_ < a; i++)
      if (vertices.find(edges[i].u_) != vertices.find(edges[i].v_)) {
        vertices.do_union(edges[i].u_, edges[i].v_);
        cost += edges[i].weight_;
        if (vertices.nr_sets() == 1)
          break;
      }
    printf("Case #%d: %d %d\n",
      tc, cost + a * vertices.nr_sets(), vertices.nr_sets());
  }
  return 0;
}

Monday, June 16, 2014

UVa 10525 - New to Bangladesh?

Accepted date: 2014-06-16
Ranking (as of 2014-06-16): 211 out of 302
Language: C++

/*
  UVa 10525 - New to Bangladesh?

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

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

struct edge {
  int u_; // source vertex
  int v_; // destination vertex
  int t_; // time
  int l_; // length

  edge() : u_(-1), v_(-1), t_(-1), l_(-1) {}
  edge(int u, int v, int t, int l) : u_(u), v_(v), t_(t), l_(l) {}
};

pair<int, int> bellman_ford(int n, int s, int t, const vector<edge>& edges)
{
  // apply the Bellman-Ford's shortest path algorithm
  // initialize the graph
  vector< pair<int, int> > distances(n,
    make_pair(numeric_limits<int>::max(), numeric_limits<int>::max()));
  distances[s].first = distances[s].second = 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];
      long long lt = static_cast<long long>(distances[e.u_].first),
        ll = static_cast<long long>(distances[e.u_].second);
      if (lt + e.t_ < distances[e.v_].first ||
        lt + e.t_ == distances[e.v_].first && ll + e.l_ < distances[e.v_].second)
        distances[e.v_] =
          make_pair(distances[e.u_].first + e.t_, distances[e.u_].second + e.l_);
    }
  return distances[t];
}

int main()
{
  int t;
  cin >> t;
  while (t--) {
    int n, m;
    cin >> n >> m;
    vector<edge> edges(m * 2);
    for (int i = 0; i < m; i++) {
      int a, b, c, d;
      cin >> a >> b >> c >> d;
      a--; b--;
      edges[i * 2].u_ = edges[i * 2 + 1].v_ = a;
      edges[i * 2].v_ = edges[i * 2 + 1].u_ = b;
      edges[i * 2].t_ = edges[i * 2 + 1].t_ = c;
      edges[i * 2].l_ = edges[i * 2 + 1].l_ = d;
    }
    int q;
    cin >> q;
    while (q--) {
      int s, t;
      cin >> s >> t;
      pair<int, int> d = bellman_ford(n, s - 1, t - 1, edges);
      if (d.first != numeric_limits<int>::max())
        cout << "Distance and time to reach destination is " << d.second <<
          " & " << d.first << ".\n";
      else
        cout << "No Path.\n";
    }
    if (t)
      cout << endl;
  }
  return 0;
}

Sunday, June 15, 2014

UVa 10947 - Bear with me, again..

Accepted date: 2014-06-15
Ranking (as of 2014-06-15): 238 out of 517
Language: C++

/*
  UVa 10947 - Bear with me, again..

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

#include <cstdio>
#include <cmath>

const int n_max = 100;

struct island {
  int x_, y_, r_;
} islands[n_max + 2];

bool matrix[n_max + 2][n_max + 2];

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

int main()
{
  int k, m;
  while (scanf("%d %d", &k, &m) != EOF) {
    double d_max = static_cast<double>(k) * m;
    scanf("%d %d %d", &islands[0].x_, &islands[0].y_, &islands[0].r_);
      // current island
    scanf("%d %d %d", &islands[1].x_, &islands[1].y_, &islands[1].r_);
      // home island
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
      scanf("%d %d %d",
        &islands[i + 2].x_, &islands[i + 2].y_, &islands[i + 2].r_);
    for (int i = 0; i < n + 2; i++) {
      matrix[i][i] = true;
      for (int j = i + 1; j < n + 2; j++) {
        double dx = islands[i].x_ - islands[j].x_,
          dy = islands[i].y_ - islands[j].y_;
        double d = dx * dx + dy * dy,
          dr = d_max + islands[i].r_ + islands[j].r_;
        matrix[i][j] = matrix[j][i] = d <= dr * dr;
          // sqrt(d) - islands[i].r_ - islands[j].r_ <= dr
      }
    }
    floyd_warshall(n + 2);
    puts((matrix[0][1]) ? "Larry and Ryan will escape!" :
      "Larry and Ryan will be eaten to death.");
  }
  return 0;
}

Thursday, June 12, 2014

UVa 10356 - Rough Roads

Accepted date: 2014-06-12
Ranking (as of 2014-06-12): 151 out of 612
Language: C++

/*
  UVa 10356 - Rough Roads

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

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

const int n_max = 500;

struct edge {
  int v_;
  int w_;
  edge(int v, int w) : v_(v), w_(w) {}
};

vector<edge> edges[n_max];
int distances[n_max][2];
  // distances[i][0] is the distance of i-th junction riding the cycyle
  // distances[i][1] is the distance of i-th junction carrying the cycle
bool visited[n_max][2];
  // visited[i][0] is true if i-th junction has already 
  // been reached riding the cycle
  // visited[i][1] is true if i-th junction has already 
  // been reached carrying the cycle

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

int dijkstra_shortest_path(int n)
{
  for (int i = 0 ; i < n; i++) {
    distances[i][0] = distances[i][1] = numeric_limits<int>::max();
    visited[i][0] = visited[i][1] = false;
  }
  distances[0][0] = 0;
  set <pair<int, int>, distance_comparator> pq; // priority queue
  pq.insert(make_pair(0, 0));
  while(!pq.empty()) {
    pair<int, int> u = *pq.begin();
    pq.erase(pq.begin());
    visited[u.first][u.second] = true;
    if (u.first == n - 1 && u.second == 0)
      break;
    int d = distances[u.first][u.second], second = 1 - u.second;
    const vector<edge>& e = edges[u.first];
    for (size_t i = 0; i < e.size(); i++)
      if (!visited[e[i].v_][second] &&
        distances[e[i].v_][second] > d + e[i].w_) {
        pair<int, int> v = make_pair(e[i].v_, second);
        pq.erase(v); // remove v if it has already been in the queue
        distances[e[i].v_][second] = d + e[i].w_;
        pq.insert(v);
      }
  }
  return distances[n - 1][0];
}

int main()
{
  int n, r;
  for (int s = 1; cin >> n >> r; s++) {
    for (int i = 0; i < n; i++)
      edges[i].clear();
    while (r--) {
      int u, v, l;
      cin >> u >> v >> l;
      edges[u].push_back(edge(v, l));
      edges[v].push_back(edge(u, l));
    }
    int d = dijkstra_shortest_path(n);
    cout << "Set #" << s << endl;
    if (d != numeric_limits<int>::max())
      cout << d << endl;
    else
      cout << "?\n";
  }
  return 0;
}

Saturday, June 7, 2014

UVa 11709 - Trust groups

Accepted date: 2014-06-07
Ranking (as of 2014-06-07): 15 out of 643
Language: C++

/*
  UVa 11709 - Trust groups

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

#include <vector>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

const int p_max = 1000, nr_name_chars_max = 31;
struct person {
  char name_[nr_name_chars_max + 1];
} persons[p_max];

void dfs1(int i, vector< vector<int> >& edges, vector<bool>& visited,
  vector<int>& vstack) // depth-first seach for a directed graph
{
  stack<int> st;
  visited[i] = true;
  st.push(i);
  while (!st.empty()) {
    i = st.top();
    vector<int>& e = edges[i];
    bool pushed = false;
    for (int j = 0; j < e.size(); j++) {
      int k = e[j];
      if (!visited[k]) {
        visited[k] = true;
        st.push(k);
        pushed = true;
      }
      if (pushed)
        break;
    }
    if (!pushed) {
      st.pop();
      vstack.push_back(i);
    }
  }
}

void dfs2(int i, vector< vector<int> >& redges, vector<bool>& visited)
// depth-first search for the transposed graph
{
  stack<int> st;
  visited[i] = false;
  st.push(i);
  while (!st.empty()) {
    i = st.top();
    vector<int>& re = redges[i];
    bool pushed = false;
    for (int j = 0; j < re.size(); j++) {
      int k = re[j];
      if (visited[k]) {
        visited[k] = false;
        st.push(k);
        pushed = true;
      }
      if (pushed)
        break;
    }
    if (!pushed)
      st.pop();
  }
}

int compare_person(const void* p, const void* q)
{
  return strcmp(reinterpret_cast<const person*>(p)->name_,
    reinterpret_cast<const person*>(q)->name_);
}

int main()
{
  while (true) {
    int p, t;
    scanf("%d %d", &p, &t);
    while (getchar() != '\n') // discard the rest of the line
      ;
    if (!p && !t)
      break;
    for (int i = 0; i < p; i++)
      gets(persons[i].name_);
    qsort(persons, p, sizeof(person), compare_person);

    vector < vector<int> > edges(p); // edges of directed graph
    vector < vector<int> > redges(p); // edges of transposed graph
    vector<bool> visited(p, false);
    vector <int> vstack;
    while (t--) {
      person pu, pv;
      gets(pu.name_);
      gets(pv.name_);
      int u = reinterpret_cast<person*>(
        bsearch(&pu, persons, p, sizeof(person), compare_person)) - persons,
        v = reinterpret_cast<person*>(
        bsearch(&pv, persons, p, sizeof(person), compare_person)) - persons;
      edges[u].push_back(v);
      redges[v].push_back(u);
    }
    // calculate number of strongly connected components
    for (int i = 0; i < p; i++)
      if (!visited[i])
        dfs1(i, edges, visited, vstack);
    int nr_scc = 0;
    for (int i = vstack.size() - 1; i >= 0; i--)
      if (visited[vstack[i]]) {
        nr_scc++;
        dfs2(vstack[i], redges, visited);
      }
    printf("%d\n", nr_scc);
  }
  return 0;
}

Thursday, June 5, 2014

UVa 11459 - Snakes and Ladders

Accepted date: 2014-06-05
Ranking (as of 2014-06-05): 279 out of 661
Language: C++

/*
  UVa 11459 - Snakes and Ladders

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

#include <cstdio>

const int die_max = 6, nr_squares = 100, nr_players_max = 1000000;

int players[nr_players_max]; // players[i] is the current square # of i-th player
int squares[nr_squares + die_max];
  // squares[i] is the next square to advance for i-th (i > 0) square

int main()
{
  int tc;
  scanf("%d", &tc);
  while (tc--) {
    int i, j, k;
    for (i = 1; i < nr_squares; i++)
      squares[i] = i;
    for ( ; i < nr_squares + die_max; i++)
      squares[i] = nr_squares;
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    for (i = 0; i < a; i++)
      players[i] = 1;
    for (i = 0; i < b; i++) {
      scanf("%d %d", &j, &k);
      squares[j] = k;
    }
    bool game_over = false;
    for (i = 0; i < c; i++) {
      scanf("%d", &j);
      if (!game_over) {
        int& p = players[i % a];
        if ((p = squares[p + j]) == nr_squares)
          game_over = true;
      }
    }
    for (i = 0; i < a; i++)
      printf("Position of player %d is %d.\n", i + 1, players[i]);
  }
  return 0;
}

Wednesday, June 4, 2014

UVa 957 - Popes

Accepted date: 2014-06-04
Ranking (as of 2014-06-04): 139 out of 534
Language: C++

/*
  UVa 957 - Popes

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

#include <cstdio>

const int p_max = 100000;
int years[p_max];

int main()
{
  int y;
  while (scanf("%d", &y) != EOF) {
    int p, i, j, max_popes = 0, max_p, max_i, max_j;
    scanf("%d", &p);
    for (i = 0; i < p; i++)
      scanf("%d", &years[i]);
    if (p == 1) {
      max_popes = 1; max_i = max_j = 0;
    }
    else {
      i = j = 0;
      do {
        if (years[j] - years[i] < y)
          j++;
        else {
          if ((max_p = j - i) > max_popes) {
            max_popes = max_p;
            max_i = i; max_j = j - 1;
          }
          i++;
          if (j < i)
            j = i;
        }
      } while (j < p);
      if ((max_p = j - i) > max_popes) {
        max_popes = max_p;
        max_i = i; max_j = j - 1;
      }
    }
    printf("%d %d %d\n", max_popes, years[max_i], years[max_j]);
  }
  return 0;
}