This was an interview question I got asked by a recruiter, the problem is basically to calculate the shortest path of all node to every node, and my solution was the following
initiate all possible edges (without reverse A - B is the same as B-A)
Each node will be represent in the following (src, cost, current_list, dest) , the src and dest is basically all the possible edges we initiate earlier
Map:
for each edge you traverse, you duplicate your tuple and add the current
traversed node to the cost and current list.
if the node is the destination you annotate finish, if the the node is
in the current list, you annotate delete
Reduce:
Don't really need to do anything besides outputting finish and deleting
delete and let the other node go through the next round of map
And by outputting I mean for each src, dest pair only output the least cost
The recruiter say this is not efficient, I can see how this is not efficient since you are traversing combinatorialy, but the only alternative I can think of is if you have n node, then spawn n servers and do dijkstra for each node which the recruiter say is also wrong. Can someone give me some help on this problem?
Edit:
Ex. Triangle Graph
The edges are A-B, B-C, C-A with path cost of 1
Algorithm
- First we initiate all possible source destination pair keeping in mind that reverse of edge is not unique A-B, A-C, B-C (B-A, C-A, B-C is omitted)
for each source destination pair we have the following tuple
(src=A, cost=None, current_list=A, dest=B, annotate=continue)
(src=A, cost=None, current_list=A, dest=C, annotate=continue)
(src=B, cost=None, current_list=B, dest=C, annotate=continue)
Now we start the map reduce algorithm
for each tuple in the tuple list we initiate: for each neighbor of the node at the end of current_list if the next neighbor is already in the current_list set annotate = delete elif the next neighbor is the dest set annotate = finish add path cost to cost else duplicate the current node add neighbor to current_list add path cost to cost delete the current tuple
In our case
(src=A, cost=None, current_list=A, dest=B, annotate=continue)
=>
(src=A, cost=1, current_list=AB, dest=B, annotate=finish)
(src=A, cost=1, current_list=AC, dest=B, annotate=continue)
(src=A, cost=None, current_list=A, dest=C, annotate=continue)
=>
(src=A, cost=1, current_list=AC, dest=C, annotate=finish)
(src=A, cost=1, current_list=AB, dest=C, annotate=continue)
(src=B, cost=None, current_list=B, dest=C, annotate=continue)
=>
(src=B, cost=1, current_list=BC, dest=C, annotate=finish)
(src=B, cost=1, current_list=BA, dest=C, annotate=continue)
Reduce
Note: we reduce on src, dest pair, and use it as our key for every tuple in tuple list
if annotate == finish keep trace of min cost and delete tuple for each src dest pair that is not the current min then pass the current min as result elif annotate == delete delete the tuple else pass down to the next round of map
Map
Since we still have some tuple that have annotate = continue
(src=B, cost=1, current_list=BA, dest=C, annotate=continue)
=>
(src=B, cost=2, current_list=BAC, dest=C, annotate=finish)
(src=B, cost=2, current_list=BAB, dest=C, annotate=delete)
(src=A, cost=1, current_list=AC, dest=B, annotate=continue)
=>
(src=A, cost=2, current_list=ACB, dest=B, annotate=finish)
(src=A, cost=2, current_list=ACA, dest=B, annotate=delete)
(src=A, cost=1, current_list=AB, dest=C, annotate=continue)
=>
(src=A, cost=2, current_list=ABC, dest=C, annotate=finish)
(src=A, cost=2, current_list=ABA, dest=C, annotate=delete)
- Reduce
We have no continue tuples, now we just use the reduce to find the min for each src dest pair