Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding all the shortest paths between two nodes in unweighted undirected graph

I need help finding all the shortest paths between two nodes in an unweighted undirected graph.

I am able to find one of the shortest paths using BFS, but so far I am lost as to how I could find and print out all of them.

Any idea of the algorithm / pseudocode I could use?

like image 608
user1946334 Avatar asked Jan 03 '13 17:01

user1946334


People also ask

How do you find the shortest path between two nodes in a unweighted graph?

Unweighted graph: breadth-first search The root of the tree is the node you started the breadth-first search from. To find the distance from node A to any other node, we simply count the number of edges in the tree. And so we find that the shortest path between A and F is 2.

Does DFS algorithm find shortest path in any unweighted graph?

DFS does not necessarily yield shortest paths in an undirected graph. BFS would be the correct choice here. As an example, consider a graph formed by taking the corners of a triangle and connecting them.

Which algorithm finds the shortest path in any unweighted graph?

We say that BFS is the algorithm to use if we want to find the shortest path in an undirected, unweighted graph. The claim for BFS is that the first time a node is discovered during the traversal, that distance from the source would give us the shortest path.


1 Answers

As a caveat, remember that there can be exponentially many shortest paths between two nodes in a graph. Any algorithm for this will potentially take exponential time.

That said, there are a few relatively straightforward algorithms that can find all the paths. Here's two.

BFS + Reverse DFS

When running a breadth-first search over a graph, you can tag each node with its distance from the start node. The start node is at distance 0, and then, whenever a new node is discovered for the first time, its distance is one plus the distance of the node that discovered it. So begin by running a BFS over the graph, writing down the distances to each node.

Once you have this, you can find a shortest path from the source to the destination as follows. Start at the destination, which will be at some distance d from the start node. Now, look at all nodes with edges entering the destination node. A shortest path from the source to the destination must end by following an edge from a node at distance d-1 to the destination at distance d. So, starting at the destination node, walk backwards across some edge to any node you'd like at distance d-1. From there, walk to a node at distance d-2, a node at distance d-3, etc. until you're back at the start node at distance 0.

This procedure will give you one path back in reverse order, and you can flip it at the end to get the overall path.

You can then find all the paths from the source to the destination by running a depth-first search from the end node back to the start node, at each point trying all possible ways to walk backwards from the current node to a previous node whose distance is exactly one less than the current node's distance.

(I personally think this is the easiest and cleanest way to find all possible paths, but that's just my opinion.)

BFS With Multiple Parents

This next algorithm is a modification to BFS that you can use as a preprocessing step to speed up generation of all possible paths. Remember that as BFS runs, it proceeds outwards in "layers," getting a single shortest path to all nodes at distance 0, then distance 1, then distance 2, etc. The motivating idea behind BFS is that any node at distance k + 1 from the start node must be connected by an edge to some node at distance k from the start node. BFS discovers this node at distance k + 1 by finding some path of length k to a node at distance k, then extending it by some edge.

If your goal is to find all shortest paths, then you can modify BFS by extending every path to a node at distance k to all the nodes at distance k + 1 that they connect to, rather than picking a single edge. To do this, modify BFS in the following way: whenever you process an edge by adding its endpoint in the processing queue, don't immediately mark that node as being done. Instead, insert that node into the queue annotated with which edge you followed to get to it. This will potentially let you insert the same node into the queue multiple times if there are multiple nodes that link to it. When you remove a node from the queue, then you mark it as being done and never insert it into the queue again. Similarly, rather than storing a single parent pointer, you'll store multiple parent pointers, one for each node that linked into that node.

If you do this modified BFS, you will end up with a DAG where every node will either be the start node and have no outgoing edges, or will be at distance k + 1 from the start node and will have a pointer to each node of distance k that it is connected to. From there, you can reconstruct all shortest paths from some node to the start node by listing of all possible paths from your node of choice back to the start node within the DAG. This can be done recursively:

  • There is only one path from the start node to itself, namely the empty path.
  • For any other node, the paths can be found by following each outgoing edge, then recursively extending those paths to yield a path back to the start node.

This approach takes more time and space than the one listed above because many of the paths found this way will not be moving in the direction of the destination node. However, it only requires a modification to BFS, rather than a BFS followed by a reverse search.

Hope this helps!

like image 105
templatetypedef Avatar answered Sep 21 '22 01:09

templatetypedef