Finding all unique paths in an undirected graph - algorithm

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.

Related

Traversal directed graph with cycles

I wrote a script to construct a directed graph using networkx in python, and I want to get all possible path from start to end including cycles.
For example, there is a directed graph:
I want to get these paths:
A->B->D
A->B->C->D
A->B->C->B->D
A->B->C->B->C->B->D
...
As far as I know, there are many algorithms to find shortest paths or paths without cycles between 2 nodes, but I want to find paths with cycles.
Is there any algorithm to achieve this ?
Thx a lot
As noted, there is an infinite number of such paths.
However, you can still generate all of them in a lazy way by maintaining all nodes v (and path you used to reach v) you can reach from the start node in k steps for k=1,2,...; if v is your target node, remember it.
When you have to return the next path, (i) pop the first target node off list, and (ii) generate the next candidates for all non-target nodes on the list. If there is no target node on the list, repeat (ii) until you find one.
The method works assuming the path always exists. If you don't find a path in n-1 steps, where n is the number of nodes, simply report that no path exists.
Here's the pseudo code for an algorithm that generates paths from shortest to longest assuming unit weights:
class Node {
int steps
Node prev
Node(int steps=0, Node prev=null) {
prev = prev
steps = steps
}
}
class PathGenerator {
Queue<Node> nodes
Node start, target;
PathGenerator(Node start, Node target) {
start = start
target = target
nodes = new Queue<>()
nodes.add(start) // assume start.steps=0 and stat.prev=null
}
Node nextPath(int n) {
current_length = -1;
do {
node = nodes.poll()
current_length = node.steps
// expand to all others you can reach from node
for each u in node.neighbors()
list.add(new Node(node, node.steps+1))
// if node is the target, return the path
if (node == target)
return node
} while (current_length < n);
throw new Exception("no path of length <=n exists");
}
}
Beware that the list nodes can grow exponentially in the worst case (think of what happens in case you run it on a complete graph).

Computing depth of each node in a "maximally packed" DAG

(Note: I thought about asking this on https://cstheory.stackexchange.com/, but decided my question is not theoretical enough -- it's about an algorithm. If there is a better Stack Exchange community for this post, I'm happy to listen!)
I'm using the terminology "starting node" to mean a node with no links into it, and "terminal node" to mean a node with no links out of it. So the following graph has starting nodes A and B and terminal nodes F and G:
I want to draw it with the following rules:
at least one starting node has a depth of 0.
links always point from top to bottom
nodes are packed vertically as closely as possible
Using those rules, depth of for each node is shown for the graph above. Can someone suggest an algorithm to compute the depth of each node that runs in less than O(n^2) time?
update:
I tweaked the graph to show that the DAG may contain starting and terminal nodes at different depths. (This was a case that I didn't consider in my original buggy answer.) I also switched terminology from "x coordinate" to "depth" in order to emphasize that this is about "graphing" and not "graphics".
Your x coordinate of a node corresponds to the longest way from any node without incomming edges to this node in question. For a DAG it can be calculated in O(N):
given DAG G:
calculate incomming_degree[v] for every v in G
initialize queue q={v with incomming_degree[v]==0}, x[v]=0 for every v in q
while(q not empty):
v=q.pop() #retreive and delete first element
for(w in neighbors of v):
incomming_degree[w]--
if(incomming_degree[w]==0): #no further way to w exists, evaluate
q.offer(w)
x[w]=x[v]+1
x stores the desired information.
Here's one solution which is essentially a two-pass depth-first tree walk. The first pass (traverseA) traces the DAG from the starting nodes (A and B in the O.P.'s example) until encountering terminal nodes (F and G in the example). It them marks them with the maximum depth as traced through the graph.
The second pass (traverseB) starts at the terminal nodes and traces back towards the starting nodes, marking each node along the way with the node's current value OR the previous node's value minus one, whichever is smaller if the node hasn't been visited yet:
function labelDAG() {
nodes.forEach(function(node) { node.depth = -1; }); // initialize
// find and mark terminal nodes
startingNodes().forEach(function(node) { traverseA(node, 0); });
// walk backwards from the terminal nodes
terminalNodes().forEach(function(node) { traverseB(node); });
dumpGraph();
};
function traverseA(node, depth) {
var targets = targetsOf(node);
if (targets.length === 0) {
// we're at a leaf (terminal) node -- set depth
node.depth = Math.max(node.depth, depth);
} else {
// traverse each subtree with depth = depth+1
targets.forEach(function(target) {
traverseA(target, depth+1);
});
};
};
// walk backwards from a terminal node, setting each source node's depth value
// along the way.
function traverseB(node) {
sourcesOf(node).forEach(function(source) {
if ((source.depth === -1) || (source.depth > node.x - 1)) {
// source has not yet been visited, or we found a longer path
// between terminal node and source node.
source.depth = node.depth - 1;
}
traverseB(source);
});
};

A* find the second shortest path

I am trying to achieve 2nd, preferably nth shortest path using the A* pathfinding algorithm. I have implemented the shortest path already:
while(open.length > 0) {
max = worldSize;
min = -1;
for(i in open) {
if(open[i].f < max) {
max = open[i].f;
min = i;
}
}
node = open.splice(min, 1)[0];
if(node.value === nodeEnd.value) {
path = closed[closed.push(node)-1];
do {
result.push({x: path.x, y:path.y});
} while(path = path.parent);
open = closed = astar = [];
result.reverse();
} else {
neighbors = findNeighbors(node.x, node.y);
for(i = 0; i < neighbors.length; ++i) {
path = newNode(node, neighbors[i]);
if(!astar[path.value]) {
path.g = node.g + manhattanDistance(neighbors[i], node);
path.f = path.g + manhattanDistance(neighbors[i], nodeEnd);
open.push(path);
astar[path.value] = true;
}
}
closed.push(node);
}
}
What can I do? I have zero experience in this and don't even understand the algorithm to its fullest (still researching at the moment). Thank you.
So this problem is in general NP hard. Since you only need the second shortest path, you can do it tractably. Basically, given the shortest path, you generate a collection of graphs by taking the original graph and removing one edge from the shortest path. So if you have a shortest path of length N, on a graph G(E,N), you end up with N graphs of G(E-1,V). Now you run A* on each of these graphs, and the shortest one is your second shortest path, as is it the shortest path which is different from the original shortest path by at least one edge.
This also shows why it is NP hard in practice. If I want the third shortest path, I have to to the following procedure only removing one edge from each of the two shortest paths, and the number of such pairs grows exponentially. N->N^2->N^3 etc
if(node.value === nodeEnd.value) is search termination condition. It means that the algorithm found some path from start to end. The essense of A* and, specifically, properties of heuristic function (admissability and consistency) guarantees that first time you arrive at termination condition gives you a shortest path.
Moreover, admissable and consistent heuristics also guarantees that all possible paths from start to end always checked from shortest to longest
So in order to get Nth closest path you only need to allow search algorithm to continue N-1 times, e.g.
hit_count = 0
while(open.length > 0) {
// same as before
if(node.value === nodeEnd.value) {
path = closed[closed.push(node)-1];
hit_count += 1;
if (hit_count == N - 1) {
do {
result.push({x: path.x, y:path.y});
} while(path = path.parent);
open = closed = astar = [];
result.reverse();
}
}
else {
// same as before
}
}
Please note that such an approach will yield paths of the same length as new paths, i.e. if you have two paths of exaclty same length one of them would be reported as shortest and other as second shortest, depending on details of implementation.
If you want to consider all paths with the same length "identical", so "second-shortest" actually longer than shortest, just replace hit_count += 1 to
// Don't forget to initialize last_found_path_length outside the loop to zero
if (path.length() != last_found_path_length) {
last_found_path_length = path.length();
hit_count += 1
}
Plase note that you haven't specified what language it is (feels like Javascript) so examples here might contain syntactic errors or refer to missing methods. But I hope the approach is clear.
An approximate solution is to run the A* algorithm multiple times with the following caveat:
After you find the current shortest path
mark the node that came right before the end node
next time you run the algorithm, don't allow that node to be used e.g. set it's path.f value to infinity or something huge. or just don't add it to the open list when it is a neighbor of your current node.
the newly found path will be the next shortest
A couple of notes:
This is approximate
It will not work after all the nodes connected to the end have been cycled through.
In terrain with a complicated set of paths and obstacles you may cut off the possible routes
if the next shortest path could be acheived by making a decision earlier in the path finding algorithm you won't capture it. to capture that you would have to cycle through the whole path in the manner described disallowing one node at a time and taking shortest path of all the possible computed paths - this will become a mess and get out of hand quickly as the number of nodes increase.
hope that helps.

How to find all shortest paths

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

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?
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!
#templatetypedef is correct, but he forgot to mention about distance check that must be done before any parent links are added to node. This means that se keep the distance from source in each of nodes and increment by one the distance for children. We must skip this increment and parent addition in case the child was already visited and has the lower distance.
public void addParent(Node n) {
// forbidding the parent it its level is equal to ours
if (n.level == level) {
return;
}
parents.add(n);
level = n.level + 1;
}
The full java implementation can be found by the following link.
http://ideone.com/UluCBb
I encountered the similar problem while solving this https://oj.leetcode.com/problems/word-ladder-ii/
The way I tried to deal with is first find the shortest distance using BFS, lets say the shortest distance is d. Now apply DFS and in DFS recursive call don't go beyond recursive level d.
However this might end up exploring all paths as mentioned by #templatetypedef.
First, find the distance-to-start of all nodes using breadth-first search.
(if there are a lot of nodes, you can use A* and stop when top of the queue has distance-to-start > distance-to-start(end-node). This will give you all nodes that belong to some shortest path)
Then just backtrack from the end-node. Anytime a node is connected to two (or more) nodes with a lower distance-to-start, you branch off into two (or more) paths.
templatetypedef your answer was very good, thank you a lot for that one(!!), but it missed out one point:
If you have a graph like this:
A-B-C-E-F
| |
D------
Now lets imagine I want this path:
A -> E.
It will expand like this:
A-> B -> D-> C -> F -> E.
The problem there is,
that you will have F as a parent of E, but
A->B->D->F-E is longer than
A->B->C->E. You will have to take of tracking the distances of parents you are so happily adding.
Step 1: Traverse the graph from the source by BFS and assign each node the minimal distance from the source
Step 2: The distance assigned to the target node is the shortest length
Step 3: From source, do a DFS search along all paths where the minimal distance is increased one by one until the target node is reached or the shortest length is reached. Print the path whenever the target node is reached.
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> ... -> sk such that:
Every adjacent pair of words differs by a single letter.
Every si for 1 <= i <= k is in wordList. Note that beginWord does not need to be in wordList.
sk == endWord
Given two words, beginWord and endWord, and a dictionary wordList, return all the shortest transformation sequences from beginWord to endWord, or an empty list if no such sequence exists. Each sequence should be returned as a list of the words [beginWord, s1, s2, ..., sk].
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: [["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
Explanation: There are 2 shortest transformation sequences:
"hit" -> "hot" -> "dot" -> "dog" -> "cog"
"hit" -> "hot" -> "lot" -> "log" -> "cog"
Example 2:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence.
https://leetcode.com/problems/word-ladder-ii
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> result = new ArrayList<>();
if (wordList == null) {
return result;
}
Set<String> dicts = new HashSet<>(wordList);
if (!dicts.contains(endWord)) {
return result;
}
Set<String> start = new HashSet<>();
Set<String> end = new HashSet<>();
Map<String, List<String>> map = new HashMap<>();
start.add(beginWord);
end.add(endWord);
bfs(map, start, end, dicts, false);
List<String> subList = new ArrayList<>();
subList.add(beginWord);
dfs(map, result, subList, beginWord, endWord);
return result;
}
private void bfs(Map<String, List<String>> map, Set<String> start, Set<String> end, Set<String> dicts, boolean reverse) {
// Processed all the word in start
if (start.size() == 0) {
return;
}
dicts.removeAll(start);
Set<String> tmp = new HashSet<>();
boolean finish = false;
for (String str : start) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
char old = chars[i];
for (char n = 'a' ; n <='z'; n++) {
if(old == n) {
continue;
}
chars[i] = n;
String candidate = new String(chars);
if (!dicts.contains(candidate)) {
continue;
}
if (end.contains(candidate)) {
finish = true;
} else {
tmp.add(candidate);
}
String key = reverse ? candidate : str;
String value = reverse ? str : candidate;
if (! map.containsKey(key)) {
map.put(key, new ArrayList<>());
}
map.get(key).add(value);
}
// restore after processing
chars[i] = old;
}
}
if (!finish) {
// Switch the start and end if size from start is bigger;
if (tmp.size() > end.size()) {
bfs(map, end, tmp, dicts, !reverse);
} else {
bfs(map, tmp, end, dicts, reverse);
}
}
}
private void dfs (Map<String, List<String>> map,
List<List<String>> result , List<String> subList,
String beginWord, String endWord) {
if(beginWord.equals(endWord)) {
result.add(new ArrayList<>(subList));
return;
}
if (!map.containsKey(beginWord)) {
return;
}
for (String word : map.get(beginWord)) {
subList.add(word);
dfs(map, result, subList, word, endWord);
subList.remove(subList.size() - 1);
}
}
}

Resources