How to find all shortest paths - algorithm

I have a graph and I want to find all shortest paths between two nodes. I've found a shortest path between two nodes by BFS. However, it just gives me one of the shortest paths if there exists one more than.
How could I get all of them using BFS?
I've implement my code from well-known BFS pseudocode.
Also, I have a adjacency list vector which holds adjacency vertices for all nodes.

You can easily do it by maintaining a list or vector of parents for each node.
If two or more nodes ( say X, Y, Z) at the same distance from the starting node , leads to another node M , make all X , Y and Z as the parents of M.
You just have to add a check to see while adding a parent to the node whether that parent is in the same level as the previous parents.
By level , I mean the distance from the starting point.
This way you can get all the shortest paths by tracing back the parent vectors.
Below is my C++ implementation.
I hope you know how to print the paths by starting from the destination ,tracing the parents and reach the starting point.
EDIT : Pseudo Code
bfs (start , end)
enqueue(start)
visited[start] = 1
while queue is NOT empty
currentNode = queue.front()
dequeue()
if(currentNode == end)
break
for each node adjacent to currentNode
if node is unvisited
visited[node] = visited[curr] + 1
enqueue(node)
parent[node].add(currentNode)
else if(currentNode is in same level as node's parents)
parent[node].add(currentNode)
return

If the graph is large, finding all paths from start to end and then selecting the shortest ones can be very inefficient. Here is a better algorithm:
Using BFS, label each node with its distance from the start node. Stop when you get to the end node.
def bfs_label(start, end):
depth = {start: 0}
nodes = [start]
while nodes:
next_nodes = []
for node in nodes:
if node == end:
return depth
for neighbor in neighbors(node):
if neighbor not in depth:
depth[neighbor] = depth[node] + 1
fringe.append(neighbor)
Using DFS, find all paths from the start node to the end node such that the depth strictly increases for each step of the path.
def shortest_paths(node, end, depth, path=None):
if path is None:
path = []
path.append(node)
if node == end:
yield tuple(path)
else:
for neighbor in neighbors(node):
if neighbor in depth and depth[neighbor] == depth[node]+1:
for sp in shortest_paths(neighbor, end, depth, path):
yield sp
path.pop()

A simpler way is to find all paths from source to destination using dfs. Now find the shortest paths among these paths. Here is a sudo code:
dfs(p,len)
if(visited[p])
return
if(p== destination)
paths.append(len)
return
visited[p]=1
for each w adjacent to p
dfs(w,len+1)
visited[p]=0
You can find the path by maintaining an array for paths. I will leave that to you as an assignment

We can use a simple BFS algorithm for finding all the shortest paths. We can maintain the path along with the current node. I have provided the link to the python code for the same below.
https://gist.github.com/mridul111998/c24fbdb46492b57f7f17decd8802eac2

Related

Returning all shortest paths in lowest run time and complexity

This post has is the result that constantly appears for this problem but doesn't provide an optimal solution.
Currently I am trying to return all shortest paths starting atfrom and ending at target using BFS but I am running into a bottleneck with either my algorithm or the data structures I use.
pseudocode:
// The graph is an adjacency list of type unordered_map<string, unordered_set<string>>
// deque with pair of (visited unordered_set, vector with current path)
deque q = [({from}, [from]);
while q:
pair = q.dequeue()
visited = pair.first
path = pair.second
foreach adjacent_node to path[-1] in the graph:
if (adjacent_node == target):
res.append(path + [adjacent_node])
else if adjacent_node not in visited:
newPath = path + [adjacent_node]
visited.add(adjacent_node)
q.push((visited, newPath))
Currently the bottleneck seems to be with the queue's pair of items. I'm unsure how to solve the problem without storing a visited set with every path, or without copying a new path into the queue.
Firstly you should know that number of shortest paths can be huge and returning them all is not practical. Consider a graph with 2k+1 layers numbered from 1 to 2k+1, in which each layer is fully connected with the next layer, and odd layers has only one point while even layers has q points. Although this graph only has k(q+1)+1 nodes and kq edges, there are in total q^k different shortest paths which can be inefficient for normal computers to handle. However if you're sure that the number of shortest paths is relatively small I can introduce the following algorithm.
The basic idea is to store a list back for each node, meaning the shortest distance between from and x equals to the shortest distance between from and v plus one if and only if v in back[x]. back[x] can be computed during the process. Then you can perform a depth-first search to print all the shortest path. Pseudo code (BTW I noticed that your code is not correct):
queue q = [ from ]
visited = set<node>
back = map<node, list<node>>
while q.not_empty():
now = q.front()
if (now == target):
continue
foreach adjacent_node to now in the graph:
if (adjacent_node in visited):
back[adjacent_node].push(now)
else:
visited.add(adjacent_node)
back[adjacent_node] = [ now ]
q.push(adjacent_node)
# Now collect all shortest paths
ret = []
current = []
def collect(x):
current.push(x)
if (x == from):
ret.push(current.reversed())
return
foreach v in back[x]:
collect(v)
current.pop()
Sorry for my poor English. Feel free to point out my typos and mistakes.

Visiting edges in a graph

I am using DFS algorithm and want to mark each edges as visited,An approach would be to look for the node and replace it with some sentinel but that would be costly,if i make an adjacency list to store the value corresponding to the node visited that would increase the lookup time,A matrix would consume a lot of space. what is the best algorithm to do so?
You just need to maintain a set of vertex pairs. E.g in Java HashMap<Pair<Vertex, Vertex>>. In Python, a Set of 2-element tuples.
The visiting of an edge occurs as you're enumerating the descendants of a new vertex just discovered and adding them to the DFS stack. If you're using a recursive DFS, then it's as you're making a recursive call on each descendant. Here's the stack version:
dfs(graph)
visitedVertices = \emptyset
visitedEdges = \emptyset
// Try all vertices as search roots
for each vertex r in graph
push r onto empty stack
while notEmpty(stack)
u = pop stack
if u not in visitedVertices
add u to visitedVertices
foreach v such that u->v is in graph
add (u,v) to visitedEdges // Visit the edge
push v on stack
Having said that, I'm not sure why you want to do this. Correctly implemented DFS naturally traverses each edge exactly once. You can prove this to yourself by looking at the algorithm above. Visiting (u,v) is only possible if u has never been visited before.
Perhaps you have some other thread that's watching search progress or are actually adding other info to edges as you visit?
I had to solve the same problem.
In my code, a graph is represented as an adjacency list: graph[i] - is a list of nodes for given vertex i.
I made a set, in which I store visited edges. An edge is a tuple of size two.
Depth-Search First:
def visit_and_print_node(node):
"""Node visitor"""
print(str(node))
def dsf_edges(graph, node_visitor_function=visit_and_print_node, starting_node=0):
"""
Performs depth-first search algorithm on the edges of the graph.
Note, here we visit edges, so it is OK for us to visit the same node more than once.
"""
visited_edges = set()
# next node to be visited is the last inserted element of the stack.
stack = []
next_nodes = graph[starting_node]
node_visitor_function(starting_node)
for node in next_nodes:
stack.append((starting_node, node))
while len(stack) > 0:
visited_edge = stack.pop()
if visited_edge in visited_edges:
continue
visited_node = visited_edge[1]
# visit node
node_visitor_function(visited_node)
visited_edges.add(visited_edge)
next_nodes = graph[visited_node]
for node in next_nodes:
if not (visited_node, node) in visited_edges:
stack.append((visited_node, node))
If you would like to see other examples, BSF on edges (use queue instead of stack), or on nodes (visiting each node once), check my git repository:
Other useful links:
https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/graphtheory/EulerianPathDirectedEdgesAdjacencyList.java
https://www.youtube.com/watch?v=8MpoO2zA2l4

Find all paths between two nodes using DFS in weighted directed graph

I had a directed weighted graph G, where weight is duration of transition.
I wrote all paths search algorithm between two vertices using DFS with modification: the search continues until total weight of path (the sum of the weights of its parts) will be less some value.
My code works in small graph, but in big graph (|V|=1800, |E|=50870) it freezes.
def find_paths(self, start, end, weight_limit=10):
res = []
def dfs(start, end, path=[], weight=0):
path = path + [start]
if len(path) > 1:
weight += self.weights[(path[-2], start)]
if weight > weight_limit:
return []
if start == end:
res.append((path, weight))
return [path]
if start not in self.adjacent:
return []
paths = []
for node in self.adjacent[start]:
if node not in path:
paths.extend(dfs(node, end, path, weight))
return paths
dfs(start, end)
return res
Your code seems correct (especially since it works on small graphs).
The problem is that there can be lots of paths between the nodes. For a fully connected graph the number of paths is on the order of N! which is a lot. Since you need all of them your program is going to be slow (especially if you run out of ram and need to swap things to disk).
If you limit the maximum total weight like you did in your code assuming all weights are one you still run in O(weight), which I assume you set to a large value since the graph is large.
You need to figure out if you really need all those paths.
If you are looking for the shortest path use Dijkstra or something for finding the shortest path.

Shortest path with depth first search

How can I get the shortest path using DFS. I've seen this question asked several times, but the replies are generally use BFS or a different algorithm. What about in the context of a robot traversing a maze? BFS isn't possible since it jumps from node to node and a robot would require backtracking.
Right now I am trying to solve the problem using:
def dfs(self, v):
v.visited = True
for adj in v.adj:
if adj.visited is False:
# set the parent
adj.successor = v
# explore the other nodes
self.dfs(adj)
However, this does not necessarily return the shortest path. Is there another way to approach this problem? I've seen some suggestions to use depth first iterative deepening, but I can't find many examples implementing this algorithm.
If anyone is interested in how I solved this here is my solution:
def dfs(self, v):
if v.successor is None: # this is the root node
v.cost = 0
v.visited = True
for adj in v.adj:
if adj.visited is False:
# set the parent
adj.successor = v
adj.cost = v.cost + 1
self.dfs(adj)
# if the cost is less switch the successor
# and set the new cost
elif adj.cost > v.cost + 1:
adj.successor = v
adj.cost = v.cost + 1
self.dfs(adj)
This is essentially a version of DFS that keeps track of the cost for each vertex. If the cost of the vertex is more than a successor + 1 step then it sets the new successor. This allows for finding the shortest path without using BFS.

Finding all unique paths in an undirected graph

I have a problem where I need to search for all unique paths in an undirected graph of degree <=4. The graph is basically a grid, and all connections are between direct neighbors only (4-way).
A path cannot visit the same vertex
more than once.
A path can visit any
number of vertices to make a path.
A path contains at least 2 vertices.
How do I go about this problem?
Here's the pseudocode I just came up with:
Start at any node.
Get all of its paths
See where they lead, if it's a node that has not been visited then visit it.
Call the same function recursively for the nodes from the previous paths.
Keep a counter for the number of paths.
This would be this code in Java (untested):
public int getPaths (Node n, Set<Node> nodesVisited) {
int pathCount = 0;
for (Path p : n.getPaths()) {
Node otherSide = p.getOtherNode(n); // Where this function basically takes a node and gets the other node in the path
if (!(nodesVisited.contains(otherSide))) {
nodesVisited.add(otherSide);
pathCount += 1 + getPaths(otherSide, new Set<Nodes>(nodesVisited));
}
}
return pathCount;
}
This should find the paths from one starting node. You can start it on each node but you'd get some duplicates. To weed them out you'd also need to return the paths though.

Resources