USACO 1.1 Greedy Gift Givers

The algorithm is simple but it is a pain in the ass to parse input and extract names.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace std;

struct Person {
int size;
vector<Person*> toList;
int money;
int left;
int sum;
string name;

Person(string name) : size(0), money(0), left(0), name(name) {}
};

int main() {
ofstream fout ("gift1.out");
ifstream fin ("gift1.in");

string input;
getline(fin, input);
int total = stoi(input);

// Each line contains the name of a group member
unordered_map<string, Person*> hashmap;
vector<Person*> personList;
for (int i = 0; i < total; ++i) {
string name;
getline(fin, name);
auto person = new Person(name);
hashmap[name] = person;
personList.push_back(person);
}

/*
The first line in the group tells the person's name who will be giving gifts.
The second line in the group contains two numbers: The initial amount of money (in the range 0..2000) to be divided up into gifts by the giver and then the number of people to whom the giver will give gifts, NGi (0 ≤ NGi ≤ NP-1).
If NGi is nonzero, each of the next NGi lines lists the the name of a recipient of a gift.
*/
for (int i = 0; i < total; ++i) {
string name;
getline(fin, name);
auto person = hashmap[name];

fin >> person->money >> person->size;
string newline;
getline(fin, newline);

if (!person->size)
person->left = person->money;
else if (person->size == 1)
person->left = 0;
else
person->left = person->money % person->size;

person->sum = person->left;

if (person->size) {
for (int j = 0; j < person->size; ++j) {
string toName;
getline(fin, toName);
person->toList.push_back(hashmap[toName]);
}
}
}

for (auto &item : hashmap) {
if (!item.second->size) continue;
int money = (item.second->money - item.second->left) / item.second->size;
for (auto &toPerson : item.second->toList) {
toPerson->sum += money;
}
}

for (auto &person : personList) {
fout << person->name << " " << person->sum - person->money << endl;
}

return 0;
}


USACO 1.1 - Your Ride Is Here

The easiest problem in USACO training.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
ofstream fout("ride.out");
ifstream fin("ride.in");

string comet, group;
getline(fin, comet);
getline(fin, group);

long long valComet = 1;
long long valGroup = 1;

for (char &c : comet)
valComet *= (c - 'A' + 1);
valComet %= 47;

for (char &c : group)
valGroup *= (c - 'A' + 1);
valGroup %= 47;

if (valComet == valGroup)
fout << "GO" << endl;
else
fout << "STAY" << endl;

return 0;
}

A C++ implementation of DijKstra Algorithm

DijKstra is a very useful algorithm used in graph search for finding single source shortest path. Devils are in details, here is a caninocal implementation of the algorithm in C++.

Like many graph problems, figure out the data structure and the representation of the graph is critical to the implementation of algorithm. Here we use graph’s object-pointer representation which naturally encodes both node relationships and edge weights.

To be able to reconstruct the shortest path we need to keep a vector that stores the ‘previous’ relationship for each vertice while we are figuring out the shortest path.

Dijkstra_Animation

// [to node index, edge weight] pair.
typedef std::pair<int, int> edge;
// [node index, distance to source] pair.
typedef std::pair<int, int> element;
class compare {
public:
bool operator()(const element&a, const element &b) {
return a.second > b.second;
}
};

int dijkstra(const vector<vector<edge>> &graph, int source, int target,
vector<int> &path) {
int size = (int)graph.size();
if (!size) return -1;
if (source < 0 || source >= size || target < 0 || target >= size)
return -1;
vector<bool> visited(size, false);
vector<int> distance(size, INT_MAX);
vector<int> prev(size, -1);
path = prev;
distance[source] = 0;

priority_queue<element, vector<element>, compare> pq;
pq.emplace(make_pair(source, 0));

while (!pq.empty()) {
int v = pq.top().first;
pq.pop();
if (v == target) return distance[v];

if (visited[v]) continue;
for (auto &edge : graph[v]) {
int u = edge.first; // vertice u that connects to v.
int w = edge.second; // weight of edge that connects u and v.
if (visited[u]) continue;
if (distance[v] + w < distance[u]) {
distance[u] = distance[v] + w;
pq.emplace(make_pair(u, distance[u]));
path[u] = v;
}
}
visited[v] = true;
}

return -1;
}

int main(int argc, const char * argv[]) {
vector<vector<edge>> graph(7, vector<edge>());
graph[1].push_back(make_pair(3, 9));
graph[1].push_back(make_pair(2, 7));
graph[1].push_back(make_pair(6, 14));
graph[2].push_back(make_pair(1, 7));
graph[2].push_back(make_pair(3, 10));
graph[2].push_back(make_pair(4, 15));
graph[3].push_back(make_pair(1, 9));
graph[3].push_back(make_pair(6, 2));
graph[3].push_back(make_pair(4, 11));
graph[4].push_back(make_pair(2, 15));
graph[4].push_back(make_pair(3, 11));
graph[4].push_back(make_pair(5, 6));
graph[5].push_back(make_pair(6, 9));
graph[5].push_back(make_pair(4, 6));
graph[6].push_back(make_pair(1, 14));
graph[6].push_back(make_pair(3, 2));
graph[6].push_back(make_pair(5, 9));

vector<int> pre;
int shortestPath = dijkstra(graph, 1, 5, pre);
cout << "Shortest path from 1 to 5 has length of " << shortestPath << endl;

// Construct shortest path.
int u = 5;
stack<int> path;
while (pre[u] != -1) {
path.push(u);
u = pre[u];
}
path.push(u);

while (!path.empty()) {
cout << path.top() << " ";
path.pop();
}
return 0;

}