This is my code that implements Dijkstra's single source shortest path algorithm, which is called multiple times to recalculate after graph changes. the graph is a road system of a city and shortest path needs to be calculated when certain roads close one at a time.
I am looking for advice on the following:
- Will this read better if it is object oriented? I guess that is a resounding yes. What kind of classes make sense? (one for adjacency list, one for list of closed roads and so on?) Is this design effort worth the time on coding competitions?
- What are other glaring design errors in my code? (I know global vars are one. Sometimes I need multiple return values - do I make a struct for each of such type of return values? Is there a less tedious design?)
I hope the question is specific enough. If not, I can add more details.
#include <iostream>
#include <queue>
#include <list>
#include <map>
using namespace std;
#define ulong unsigned long
#define INFINITY (ulong)-1
typedef struct {
ulong nbr;
ulong cost;
} ADJ_LIST_NODE;
typedef struct {
ulong shortest_dist;
ulong predecessor;
} SP_FOUND_NODE;
typedef struct {
ulong vertex;
ulong dist;
ulong predecessor;
} SP_ESTIMATE_NODE;
typedef struct {
ulong v1;
ulong v2;
} ROAD;
class SPEstimateNodeCompare {
public:
bool operator()(const SP_ESTIMATE_NODE& a, const SP_ESTIMATE_NODE& b) {
return a.dist > b.dist;
}
};
vector< map< ulong, ulong> > city_adj_list;
ulong n_cities, m_roads;
ulong src, dest;
ulong q_broken_roads;
vector<ROAD> broken_road_list;
map< ulong, SP_FOUND_NODE > sp_found;
priority_queue< SP_ESTIMATE_NODE, vector<SP_ESTIMATE_NODE>, SPEstimateNodeCompare > sp_estimate_q;
map< ulong, ulong> estimate_distances;
void read_input() {
cin >> n_cities;
cin >> m_roads;
for (ulong i = 0; i < n_cities; i++) {
city_adj_list.push_back(*(new map<ulong, ulong>));
}
ulong v1, v2, cost;
ADJ_LIST_NODE node;
for (ulong i = 0; i < m_roads; i++) {
cin >> v1;
cin >> v2;
cin >> cost;
if (v1 >= n_cities or v2 >= n_cities) {
cout << "Invalid input!" << endl;
exit(-1);
}
node.nbr = v2;
node.cost = cost;
city_adj_list[v1][v2] = cost;
node.nbr = v1;
node.cost = cost;
city_adj_list[v2][v1] = cost;
}
cin >> src;
cin >> dest;
if (src >= n_cities or dest >= n_cities) {
cout << "Invalid input - source/destination!" << endl;
exit(-1);
}
cin >> q_broken_roads;
if (q_broken_roads > m_roads) {
cout << "Invalid input - q value!" << endl;
exit(-1);
}
for (ulong i = 0; i < q_broken_roads; i++) {
ROAD r;
cin >> r.v1;
cin >> r.v2;
if (r.v1 >= n_cities or r.v2 >= n_cities) {
cout << "Invalid input! broken roads." << endl;
exit(-1);
}
broken_road_list.push_back(r);
}
}
void print_input(vector< map <ulong, ulong> >& adj_list) {
map< ulong, ulong >::iterator next_road;
for (ulong i = 0; i < n_cities; i++) {
cout << "CITY " << i << endl;
for (next_road = adj_list[i].begin();
next_road != adj_list[i].end();
next_road++) {
cout << "Neighbour " << next_road->first << " Cost " <<
next_road->second << endl;
}
}
}
void relax_estimates(ulong vertex, ulong shortest_dist, vector< map <ulong, ulong> >& adj_list) {
if (vertex >= n_cities) {
cout << "Invalid relax vertex " << vertex << endl;
}
// cout << "Relaxing w.r.t. " << vertex << endl;
map < ulong, ulong>::iterator next_road;
// For each neighbour of relax vertex,
for(next_road = adj_list[vertex].begin();
next_road != adj_list[vertex].end();
next_road++) {
// next_road->nbr ==> first/key
// next_road->cost ==> second/value
if (sp_found.count(next_road->first) == 0 and
next_road->second + shortest_dist < estimate_distances[next_road->first]) {
estimate_distances[next_road->first] = next_road->second + shortest_dist;
// cout << "Relaxed distance to " << next_road->first << " to " << estimate_distances[next_road->first] << endl;
SP_ESTIMATE_NODE x;
x.vertex = next_road->first;
x.dist = estimate_distances[next_road->first];
x.predecessor = vertex;
sp_estimate_q.push(x);
}
}
}
ulong get_shortest_path (vector< map <ulong, ulong> >& adj_list) {
SP_ESTIMATE_NODE est_node;
SP_FOUND_NODE found_node;
// Initialize data structures
for (ulong v = 0; v < n_cities; v++) {
estimate_distances[v] = INFINITY;
sp_found.erase(v);
}
while (!sp_estimate_q.empty()) {
sp_estimate_q.pop();
}
found_node.shortest_dist = 0;
found_node.predecessor = -1;
sp_found[src] = found_node;
// list<ADJ_LIST_NODE>::iterator next_road;
map <ulong, ulong >::iterator next_road;
for (next_road = adj_list[src].begin();
next_road != adj_list[src].end();
next_road++) {
// next_road->nbr ==> first/key
// next_road->cost ==> second/value
// cout << "Adding " << next_road->first << " with dist "
// << next_road->second << " to priority q" << endl;
est_node.vertex = next_road->first;
est_node.dist = next_road->second;
est_node.predecessor = src;
sp_estimate_q.push(est_node);
estimate_distances[est_node.vertex] = est_node.dist;
}
ulong relax_vertex = src;
ulong relax_vertex_dist = 0;
while (!sp_estimate_q.empty()) {
// Get smallest dist entry from q
est_node = sp_estimate_q.top();
// Make sure est_node is not a duplicate entry in priority queue
if (sp_found.count(est_node.vertex) > 0) {
// Do nothing except delete it from map and queue.
sp_estimate_q.pop();
estimate_distances.erase(est_node.vertex);
continue;
}
// cout << "Picked vertex " << est_node.vertex << " with dist "
// << est_node.dist << " from priority q" << endl;
// Add to list of shortest path found vertices.
found_node.shortest_dist = est_node.dist;
found_node.predecessor = est_node.predecessor;
sp_found[est_node.vertex] = found_node;
// Relax all its neighbours.
relax_vertex = est_node.vertex;
relax_vertex_dist = est_node.dist;
relax_estimates(relax_vertex, relax_vertex_dist, adj_list);
// Remove the resolved vertex.
estimate_distances.erase(est_node.vertex);
sp_estimate_q.pop();
}
// Print.
cout << sp_found[dest].shortest_dist << endl;
// cout << endl;
// cout << "Shortest distance " << sp_found[dest].shortest_dist << endl;
// cout << "Path (in reverse) " << dest;
// ulong v = dest;
// while (v != src) {
// v = sp_found[v].predecessor;
// cout << " - " << v;
// }
// cout << endl;
return 0;
}
int main() {
read_input();
// cout << ">>>>> Before broken roads " << endl;
// get_shortest_path(city_adj_list);
for (ulong i = 0; i < q_broken_roads; i++) {
vector< map< ulong, ulong> > city_broken_adj_list = city_adj_list;
// ROAD broken_road_list[i];
ulong v1 = broken_road_list[i].v1;
ulong v2 = broken_road_list[i].v2;
city_broken_adj_list[v1].erase(v2);
city_broken_adj_list[v2].erase(v1);
// cout << ">>>>> Broken road " << v1 << "==" << v2 << endl;
// print_input(city_broken_adj_list);
get_shortest_path(city_broken_adj_list);
}
}