The official problem description is here, which in my opinion is unclear and quite long. Below is my description. I recommend you still read the official description, it has details such as input and output format
Input: N cows
- represented as points on a 2D graph (integer
x, y
pairs) - each with an integer walkie-talkie power P, the maximum distance that cow can transmit
Output/Problem: What's the maximum number of cows a broadcast from any single cow can reach?
- Cows can relay messages to and from each other, like in a digital network
Cow A might be able to transmit to Cow B even if Cow B cannot transmit back, due to Cow A's power being larger than that of Cow B.
- The output number should include the originating cow.
Context
I did this for problem for practice. You have three hours to take the actual contest and graded on the number of test cases your program can pass within the time limit. There are three problems total. This solution passes all 10.
Issues
- Verbosity
- Readability
- Performance
- Code-writing Efficiency, e.g. repetition
Faster algorithms exist, but implementing complex algorithms takes more time. The less time spent implementing, the more time I have to work on the other problems.
Regarding using namespace std;
- single file programs don't have the namespace conflict problems more complex ones do.
#include <vector>
#include <iostream>
#include <unordered_map>
#include <map>
#include <fstream>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
void split(const string &s, vector<int> &elems) {
stringstream ss;
ss.str(s);
string item;
while (getline(ss, item, ' ')) {
elems.push_back(stoi(item));
}
}
vector<int> split(const string &s) {
vector<int> elems;
split(s, elems);
return elems;
}
tuple<int, int, int> inline split_tuple(ifstream &stream) {
string str;
getline(stream, str);
istringstream iss(str);
vector<int> tokens = split(str);
return tuple<int, int, int>{tokens[0], tokens[1], tokens[2]};
}
int inline distance(const tuple<int, int, int> a, const tuple<int, int, int> b) {
// without the sqrt(), to make it faster
// --- note: To me, an extra typecast to int is no more readable, and just adds extra fluff.
return pow(get<0>(a) - get<0>(b), 2) + pow(get<1>(a) - get<1>(b), 2);
}
int main() {
ifstream input("moocast.in");
string line;
getline(input, line);
int n = stoi(line);
vector<int> temp;
vector<tuple<int, int, int>> cows;
for (int i = 0; i < n; ++i) {
cows.push_back(split_tuple(input));
}
unordered_map<int, vector<int>> cow_graph;
// initialize cow_graph
for (int i = 0; i < cows.size(); ++i) {
cow_graph[i] = {};
}
// fill out cow_graph
for (int i = 0; i < cows.size(); ++i) {
tuple<int, int, int> cow = cows[i];
int cur_power = pow(get<2>(cow), 2);
for (int j = 0; j < cows.size(); ++j) {
tuple<int, int, int> cow2 = cows[j];
if (distance(cow, cow2) <= cur_power) {
cow_graph[i].push_back(j);
}
}
}
// do bfs
set<int> seen;
stack<int> queue;
int highest = 0;
for (int i = 0; i < cows.size(); ++i) {
tuple<int, int, int> cow = cows[i];
queue.empty();
seen.clear();
queue.push(i);
while (!queue.empty()) {
int v = queue.top();
queue.pop();
if (seen.count(v) == 0) {
seen.insert(v);
for (auto &&adjacent : cow_graph[v]) {
queue.push(adjacent);
}
}
}
if (seen.size() > highest) {
highest = seen.size();
}
}
ofstream output("moocast.out");
output << highest;
}
My solution first computes which cows can call other cows and formats it as a directed graph. It then performs BFS for every node in this graph, keeping track of the largest number of nodes seen from each iteration, outputting that number.
distance()
calculates Euclidean Distance, squared - the sqrt()
function is computationally expensive and A^2 < B^2
only when A < B
.
split*
are helper functions for getting input.