I tried out this Codejam problem and produced a valid solution in C++. There is a Python solution on the website. Was wondering if any C++ people would offer some improvements/optimizations to this solution. Thanks!
BTW: In Codejam the goal is to write code as fast as possible (a reason why Python would have been a better language choice) but I'm interested in improving the solution.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <assert.h>
#include <stdlib.h>
// Watershed Practice Problem
// http://code.google.com/codejam/contest/dashboard?c=90101#s=p1
using namespace std;
#ifdef DEBUG
static int running_time;
#endif
void SplitString(const string &s,
char delim,
vector<string> &elems) {
stringstream ss(s);
string item;
while(getline(ss, item, delim)) {
elems.push_back(item);
}
}
void PrintMap(const char map[], int height, int width) {
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
cout << map[(i * width) + j] << " ";
}
cout << endl;
}
}
void MinNeighbor(const int altitude_map[],
int height, int width,
int i, int j,
int & n_i, int & n_j) {
int min_altitude = altitude_map[(i * width) + j];
n_i = i;
n_j = j;
// North.
if ((i - 1) >= 0
&& altitude_map[((i - 1) * width) + j] < min_altitude) {
min_altitude = altitude_map[((i - 1) * width) + j];
n_i = i - 1;
n_j = j;
}
// West.
if ((j - 1) >= 0
&& altitude_map[(i * width) + (j - 1)] < min_altitude) {
min_altitude = altitude_map[(i * width) + (j - 1)];
n_i = i;
n_j = j - 1;
}
// East.
if ((j + 1) < width
&& altitude_map[(i * width) + (j + 1)] < min_altitude) {
min_altitude = altitude_map[(i * width) + (j + 1)];
n_i = i;
n_j = j + 1;
}
// South.
if ((i + 1) < height
&& altitude_map[((i + 1) * width) + j] < min_altitude) {
min_altitude = altitude_map[((i + 1) * width) + j];
n_i = i + 1;
n_j = j;
}
}
void Drain(const int altitude_map[],
char label_map[],
char & label,
int height, int width,
int i, int j) {
int n_i = 0;
int n_j = 0;
MinNeighbor(altitude_map, height, width, i, j, n_i, n_j);
#ifdef DEBUG
cout << endl;
cout << "The min neighbor of : (" << i << "," << j << ") ";
cout << "is (" << n_i << "," << n_j << ")" << endl;
#endif
if (altitude_map[(n_i * width) + n_j] < altitude_map[(i * width) + j]) {
// We are draining into an existing basin; use its label.
if (label_map[(n_i*width) + n_j] != '-')
label = label_map[(n_i*width) + n_j];
else // Drain into the neighboring cell with the smallest altitude.
Drain(altitude_map, label_map, label, height, width, n_i, n_j);
}
label_map[(i*width) + j] = label;
#ifdef DEBUG
++running_time;
#endif
}
int main(int argc, char *argv[]) {
string file_name;
if (argc < 2)
file_name = "B-tiny-practice.in";
else
file_name = argv[1];
ifstream input_file;
input_file.open(file_name.c_str());
assert(input_file.is_open());
string line;
// The first line contains the number of maps.
getline(input_file, line);
int num_maps = atoi(line.c_str());
int case_num = 1;
while (case_num <= num_maps) {
assert(!input_file.eof());
getline(input_file, line); // Line should have two numbers: W H.
size_t delim = line.find(" ");
int height = atoi(line.substr(0, delim).c_str());
int width = atoi(line.substr(delim + 1).c_str());
int altitude_map[height * width];
char label_map[height * width];
// Populate the altitude map and initialize the label map.
for (int i = 0; i < height; ++i) {
assert(!input_file.eof());
getline(input_file, line);
vector<string> row;
SplitString(line, ' ', row);
int j = 0;
for (vector<string>::const_iterator ci = row.begin();
ci != row.end(); ++ci) {
label_map[(i * width) + j] = '-';
altitude_map[(i * width) + j++] = atoi(ci->c_str());
}
}
char current_label = 'a';
// Populate the labels.
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
if (label_map[(i * width) + j] == '-') {
char label = current_label;
Drain(altitude_map, label_map, label, height, width, i, j);
if (label == current_label)
++current_label;
}
}
}
cout << "Case #" << case_num++ << ":" << endl;
PrintMap(label_map, height, width);
#ifdef DEBUG
cout << endl << "Running Time: " << running_time << endl;
running_time = 0;
#endif
}
input_file.close();
return 0;
}
// vim:set sw=2 sts=2 ts=2: