I'm trying to solve a question from Sedgewick & Wayne's Algorithms book: the single-source shortest bitonic path.
Some definitions for those that are not familiar with the problem:
Monotonic shortest-path: a monotonic shortest-path is a shortest-path in which the edges are either strictly increasing or strictly decreasing.
Bitonic shortest-path: a shortest-path from s to t in which there is an intermediate vertex v such that the weights of the edges on the path s to v are strictly increasing and the weights of the edges on the path from v to t are strictly decreasing.
The idea of the problem is:
Given an edge-weighted digraph, find a bitonic shortest path from a given source vertex to every other vertex (if one exists). The path should be simple (no repeated vertices).
What I have so far is the following:
A monotonic shortest-path can be computed by relaxing all the edges in the graph in either ascending order (to find an ascending monotonic shortest-path) or relaxing all the edges in the graph in descending order (to find a descending monotonic shortest-path).
I pre-computed the ascending monotonic shortest-path from the source vertex to all other vertices (this can be done in O(E) as it is just one shortest-paths tree).
I then pre-computed the descending monotonic shortest-path from all pairs of vertices, since any vertex can be the intermediate vertex and any vertex can be the target vertex. This is taking O(E * V) time.
Now, for each path starting from s and ending at t, I could check all the combinations of (1) ascending monotonic shortest-path from s to an intermediate vertex v and (2) descending monotonic shortest-path from v to t and select the path with lowest weight.
This would give me a bitonic shortest-path from s to t.
However, there is a catch: we cannot have repeated vertices in the path and the above idea does not address this issue.
Any ideas for solving this last part of the problem?
Any other ideas/approaches that solve the problem are also welcome.
(Note: I did not check whether the grand scheme of your idea really holds up, or whether there might be a faster algorithm. This solely addresses the issue of repeated vertices.)
Assuming that neither the decreasing- nor the increasing paths contain repeated vertices, the only chance for repeated vertices is if a vertex exists in both, the decreasing and the increasing portion of the "bitonic" path.
A --1-- B --3-- C --5-- D --7-- E --7-- D --5-- C --2-- F --1-- Z
In this example, C is in both parts of the path, with E being the intermediate vertex. As can be seen, this also means that the segment from C to E and from E to C have to be the same in both the increasing and the decreasing path. If there was a different (shorter) path in the decreasing path, then the increasing path would also be shorter when routed via that node.
This means, that we can simply cut the segment between the two instance of C and are left with an even shorter "bitonic" path. (Or, we can just ignore the longer bitonic path, as we will find the shorter one later, anyway, when considering C instead of E as the intermediate node.)
A --1-- B --3-- C --2-- F --1-- Z
This would result in seemingly weird results like A --1-- B --1-- Z, where two consecutive edges have the same weight. But according to your definition "a shortest-path from s to t in which there is an intermediate vertex v such that the weights of the edges on the path s to v are strictly increasing and the weights of the edges on the path from v to t are strictly decreasing", this should still be a bitonic path, since both A --1-- C as well as C --1-- Z are strictly monotonic increasing and decreasing, respectively.
It turns out that the answer looks simpler than I expected.
The strategy that I commented regarding (1) pre-computing the ascending monotonic shortest-path from the source vertex to all other vertices, (2) pre-computing the descending monotonic shortest-path from all pairs of vertices and, (3) for each path starting from s and ending at t, checking all combinations of ascending monotonic shortest-path from s to an intermediate vertex v and descending monotonic shortest-path from v to t works only when the paths can have repeated vertices.
When we are looking for simple paths (no repeated vertices), we can (1) relax all the edges in the graph in ascending order and then, on these same paths, (2) relax all the edges in the graph in descending order. While we are relaxing edges in ascending order we make sure to discard paths that are only descending, or that have all edges with equal weights (except when there are exactly 2 edges of same weight, see my comment on this edge case below). And when relaxing edges in descending order we discard paths with only ascending edge weights.
This is the general idea of the algorithm I came up with. There are some implementation details involved as well: a priority queue is used for both relaxations with Path objects ordered by smallest weight. It is important to take into account the edge case of a path with exactly 2 edges of equal weight (which, according to the problem definition, is a bitonic path).
The runtime complexity seems to be O(P lg P), where P is the number of paths in the graph.
The code and its dependencies and tests can be found in my GitHub, in this class: BitonicShortestPaths.java
I am also posting the main code here for reference:
public class BitonicSP {
private Path[] bitonicPathTo; // bitonic path to vertex
public BitonicSP(EdgeWeightedDigraph edgeWeightedDigraph, int source) {
bitonicPathTo = new Path[edgeWeightedDigraph.vertices()];
// 1- Relax edges in ascending order to get a monotonic increasing shortest path
Comparator<DirectedEdge> edgesComparator = new Comparator<DirectedEdge>() {
#Override
public int compare(DirectedEdge edge1, DirectedEdge edge2) {
if(edge1.weight() > edge2.weight()) {
return -1;
} else if(edge1.weight() < edge2.weight()) {
return 1;
} else {
return 0;
}
}
};
List<Path> allCurrentPaths = new ArrayList<>();
relaxAllEdgesInSpecificOrder(edgeWeightedDigraph, source, edgesComparator, allCurrentPaths,true);
// 2- Relax edges in descending order to get a monotonic decreasing shortest path
edgesComparator = new Comparator<DirectedEdge>() {
#Override
public int compare(DirectedEdge edge1, DirectedEdge edge2) {
if(edge1.weight() < edge2.weight()) {
return -1;
} else if(edge1.weight() > edge2.weight()) {
return 1;
} else {
return 0;
}
}
};
relaxAllEdgesInSpecificOrder(edgeWeightedDigraph, source, edgesComparator, allCurrentPaths, false);
}
private void relaxAllEdgesInSpecificOrder(EdgeWeightedDigraph edgeWeightedDigraph, int source,
Comparator<DirectedEdge> edgesComparator, List<Path> allCurrentPaths,
boolean isAscendingOrder) {
// Create a map with vertices as keys and sorted outgoing edges as values
Map<Integer, VertexInformation> verticesInformation = new HashMap<>();
for(int vertex = 0; vertex < edgeWeightedDigraph.vertices(); vertex++) {
DirectedEdge[] edges = new DirectedEdge[edgeWeightedDigraph.outdegree(vertex)];
int edgeIndex = 0;
for(DirectedEdge edge : edgeWeightedDigraph.adjacent(vertex)) {
edges[edgeIndex++] = edge;
}
Arrays.sort(edges, edgesComparator);
verticesInformation.put(vertex, new VertexInformation(edges));
}
PriorityQueue<Path> priorityQueue = new PriorityQueue<>();
// If we are relaxing edges for the first time, add the initial paths to the priority queue
if(isAscendingOrder) {
VertexInformation sourceVertexInformation = verticesInformation.get(source);
while (sourceVertexInformation.getEdgeIteratorPosition() < sourceVertexInformation.getEdges().length) {
DirectedEdge edge = sourceVertexInformation.getEdges()[sourceVertexInformation.getEdgeIteratorPosition()];
sourceVertexInformation.incrementEdgeIteratorPosition();
Path path = new Path(edge);
priorityQueue.offer(path);
allCurrentPaths.add(path);
}
}
// If we are relaxing edges for the second time, add all existing ascending paths to the priority queue
if(!allCurrentPaths.isEmpty()) {
for(Path currentPath : allCurrentPaths) {
priorityQueue.offer(currentPath);
}
}
while (!priorityQueue.isEmpty()) {
Path currentShortestPath = priorityQueue.poll();
DirectedEdge currentEdge = currentShortestPath.directedEdge;
int nextVertexInPath = currentEdge.to();
VertexInformation nextVertexInformation = verticesInformation.get(nextVertexInPath);
// Edge case: a bitonic path consisting of 2 edges of the same weight.
// s to v with only one edge is strictly increasing, v to t with only one edge is strictly decreasing
boolean isEdgeCase = false;
if(currentShortestPath.numberOfEdges() == 2
&& currentEdge.weight() == currentShortestPath.previousPath.directedEdge.weight()) {
isEdgeCase = true;
}
if((currentShortestPath.isDescending() || isEdgeCase)
&& (currentShortestPath.weight() < bitonicPathDistTo(nextVertexInPath)
|| bitonicPathTo[nextVertexInPath] == null)) {
bitonicPathTo[nextVertexInPath] = currentShortestPath;
}
double weightInPreviousEdge = currentEdge.weight();
while (nextVertexInformation.getEdgeIteratorPosition() < nextVertexInformation.getEdges().length) {
DirectedEdge edge =
verticesInformation.get(nextVertexInPath).getEdges()[nextVertexInformation.getEdgeIteratorPosition()];
boolean isEdgeInEdgeCase = currentShortestPath.numberOfEdges() == 1
&& edge.weight() == weightInPreviousEdge;
if(!isEdgeInEdgeCase && ((isAscendingOrder && edge.weight() <= weightInPreviousEdge)
|| (!isAscendingOrder && edge.weight() >= weightInPreviousEdge))) {
break;
}
nextVertexInformation.incrementEdgeIteratorPosition();
Path path = new Path(currentShortestPath, edge);
priorityQueue.offer(path);
// If we are relaxing edges for the first time, store the ascending paths so they can be further
// relaxed when computing the descending paths on the second relaxation
if(isAscendingOrder) {
allCurrentPaths.add(path);
}
}
}
}
public double bitonicPathDistTo(int vertex) {
if(hasBitonicPathTo(vertex)) {
return bitonicPathTo[vertex].weight();
} else {
return Double.POSITIVE_INFINITY;
}
}
public boolean hasBitonicPathTo(int vertex) {
return bitonicPathTo[vertex] != null;
}
public Iterable<DirectedEdge> bitonicPathTo(int vertex) {
if(!hasBitonicPathTo(vertex)) {
return null;
}
return bitonicPathTo[vertex].getPath();
}
}
public class Path implements Comparable<Path> {
private Path previousPath;
private DirectedEdge directedEdge;
private double weight;
private boolean isDescending;
private int numberOfEdges;
Path(DirectedEdge directedEdge) {
this.directedEdge = directedEdge;
weight = directedEdge.weight();
numberOfEdges = 1;
}
Path(Path previousPath, DirectedEdge directedEdge) {
this(directedEdge);
this.previousPath = previousPath;
weight += previousPath.weight();
numberOfEdges += previousPath.numberOfEdges;
if(previousPath != null && previousPath.directedEdge.weight() > directedEdge.weight()) {
isDescending = true;
}
}
public double weight() {
return weight;
}
public boolean isDescending() {
return isDescending;
}
public int numberOfEdges() {
return numberOfEdges;
}
public Iterable<DirectedEdge> getPath() {
LinkedList<DirectedEdge> path = new LinkedList<>();
Path iterator = previousPath;
while (iterator != null && iterator.directedEdge != null) {
path.addFirst(iterator.directedEdge);
iterator = iterator.previousPath;
}
path.add(directedEdge);
return path;
}
#Override
public int compareTo(Path other) {
if(this.weight < other.weight) {
return -1;
} else if(this.weight > other.weight) {
return 1;
} else {
return 0;
}
}
}
public class VertexInformation {
private DirectedEdge[] edges;
private int edgeIteratorPosition;
VertexInformation(DirectedEdge[] edges) {
this.edges = edges;
edgeIteratorPosition = 0;
}
public void incrementEdgeIteratorPosition() {
edgeIteratorPosition++;
}
public DirectedEdge[] getEdges() {
return edges;
}
public int getEdgeIteratorPosition() {
return edgeIteratorPosition;
}
}
Related
I just found about about the bottleneck shortest path problem, and I'm really confused about what we need to find there. Do we need to find the maximum cost edge on the path from s to t consisting of short edges, or the minimum cost edge on the path consisting of the long edges? The latter makes more sense to me, and it's described under the picture at right on wikipedia : https://en.wikipedia.org/wiki/Widest_path_problem
But when I looked at this link : http://homes.cs.washington.edu/~anderson/iucee/Slides_421_06/Lecture08_09_10.pdf
the algorithm described there doesn't seem to find the path consisting of long edges, I even implemented it and tested it on this graph:
Here's the algorithm that I took from that link above:
import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.Deque;
import java.util.PriorityQueue;
public class BSP {
private double[] d;
private DirectedWeightedEdge[] edgeTo;
private PriorityQueue<Integer> pq;
private boolean[] visited;
private class VertexComparer implements Comparator<Integer> {
public int compare(Integer one, Integer two) {
if (d[one] < d[two]) return -1;
return 1;
}
}
public BSP(WeightedDigraph G, int source) {
d = new double[G.V()];
edgeTo = new DirectedWeightedEdge[G.V()];
visited = new boolean[G.V()];
for (int i = 0; i < G.V(); ++i) d[i] = Double.POSITIVE_INFINITY;
d[source] = Double.NEGATIVE_INFINITY;
pq = new PriorityQueue<>(new VertexComparer());
pq.add(source);
while (!pq.isEmpty()) {
int top = pq.poll();
if (!visited[top])
relax(G, top);
}
}
private void relax(WeightedDigraph G, int v) {
visited[v] = true;
for (DirectedWeightedEdge e : G.adj(v)) {
if (d[e.to()] > Math.max(d[e.from()], e.weight())) {
d[e.to()] = Math.max(d[e.from()], e.weight());
edgeTo[e.to()] = e;
pq.add(e.to());
}
}
}
public boolean hasPathTo(int v) {
return edgeTo[v] != null;
}
public Iterable<Integer> pathTo(int v) {
assert hasPathTo(v);
int w = v;
DirectedWeightedEdge e = edgeTo[w];
Deque<Integer> stack = new ArrayDeque<>();
for (; edgeTo[w] != null; e = edgeTo[e.from()]) {
stack.push(w);
w = e.from();
}
stack.push(w);
return stack;
}
}
Why doesn't that algorithm also find the path consisting of long edges, from 0 to 3, for example : {0,4}, {4,3} and conclude that the answer is 4? I can't seem to understand why it finds the path 0->1->2->3 instead. Or is the problem somehow different for directed graphs?
If the algorithm described on that link is wrong, please let me know what the right algorithm is. I just can't seem to understand why 2 sources give different information.
As with many similar problems, the bottleneck problem is symmetrical. In fact, you can talk of two different problems:
Find a path that has its shortest edge as long as possible
Find a path that has its longest edge as short as possible
The algorithm for both versions is the same, except that you reverse all weight relations (change max-heap to min-heap or vice-versa, change the sign of comparison in relax(), etc.) Even the Wikipedia link you gave states:
A closely related problem, the minimax path problem, asks for the path
that minimizes the maximum weight of any of its edges. <...> Any algorithm
for the widest path problem can be transformed into an algorithm for
the minimax path problem, or vice versa, by reversing the sense of all
the weight comparisons performed by the algorithm, or equivalently by
replacing every edge weight by its negation.
Obviously, both versions can be called the bottleneck problem, and you just came across lecture notes that talks about the second version. As the algorithms are the same, no much confusion will arise, you just need to be explicit about what version do you talk about.
I am having some trouble writing an algorithm that returns all the paths forming simple cycles on an undirected graph.
I am considering at first all cycles starting from a vertex A, which would be, for the graph below
A,B,E,G,F
A,B,E,D,F
A,B,C,D,F
A,B,C,D,E,G,F
Additional cycles would be
B,C,D,E
F,D,E,G
but these could be found, for example, by calling the same algorithm again but starting from B and from D, respectively.
The graph is shown below -
My current approach is to build all the possible paths from A by visiting all the neighbors of A, and then the neighbors of the neightbors and so on, while following these rules:
each time that more than one neighbor exist, a fork is found and a new path from A is created and explored.
if any of the created paths visits the original vertex, that path is a cycle.
if any of the created paths visits the same vertex twice (different from A) the path is discarded.
continue until all possible paths have been explored.
I am currently having problems trying to avoid the same cycle being found more than once, and I am trying to solve this by looking if the new neighbor is already part of another existing path so that the two paths combined (if independent) build up a cycle.
My question is: Am I following the correct/better/simpler logic to solve this problem.?
I would appreciate your comments
Based on the answer of #eminsenay to other question, I used the elementaryCycles library developed by Frank Meyer, from web_at_normalisiert_dot_de which implements the algorithms of Johnson.
However, since this library is for directed graphs, I added some routines to:
build the adjacency matrix from a JGraphT undirected graph (needed by Meyer's lib)
filter the results to avoid cycles of length 2
delete repeated cycles, since Meyer's lib is for directed graphs, and each undirected cycle is two directed cycles (one on each direction).
The code is
package test;
import java.util.*;
import org.jgraph.graph.DefaultEdge;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.graph.SimpleGraph;
public class GraphHandling<V> {
private UndirectedGraph<V,DefaultEdge> graph;
private List<V> vertexList;
private boolean adjMatrix[][];
public GraphHandling() {
this.graph = new SimpleGraph<V, DefaultEdge>(DefaultEdge.class);
this.vertexList = new ArrayList<V>();
}
public void addVertex(V vertex) {
this.graph.addVertex(vertex);
this.vertexList.add(vertex);
}
public void addEdge(V vertex1, V vertex2) {
this.graph.addEdge(vertex1, vertex2);
}
public UndirectedGraph<V, DefaultEdge> getGraph() {
return graph;
}
public List<List<V>> getAllCycles() {
this.buildAdjancyMatrix();
#SuppressWarnings("unchecked")
V[] vertexArray = (V[]) this.vertexList.toArray();
ElementaryCyclesSearch ecs = new ElementaryCyclesSearch(this.adjMatrix, vertexArray);
#SuppressWarnings("unchecked")
List<List<V>> cycles0 = ecs.getElementaryCycles();
// remove cycles of size 2
Iterator<List<V>> listIt = cycles0.iterator();
while(listIt.hasNext()) {
List<V> cycle = listIt.next();
if(cycle.size() == 2) {
listIt.remove();
}
}
// remove repeated cycles (two cycles are repeated if they have the same vertex (no matter the order)
List<List<V>> cycles1 = removeRepeatedLists(cycles0);
for(List<V> cycle : cycles1) {
System.out.println(cycle);
}
return cycles1;
}
private void buildAdjancyMatrix() {
Set<DefaultEdge> edges = this.graph.edgeSet();
Integer nVertex = this.vertexList.size();
this.adjMatrix = new boolean[nVertex][nVertex];
for(DefaultEdge edge : edges) {
V v1 = this.graph.getEdgeSource(edge);
V v2 = this.graph.getEdgeTarget(edge);
int i = this.vertexList.indexOf(v1);
int j = this.vertexList.indexOf(v2);
this.adjMatrix[i][j] = true;
this.adjMatrix[j][i] = true;
}
}
/* Here repeated lists are those with the same elements, no matter the order,
* and it is assumed that there are no repeated elements on any of the lists*/
private List<List<V>> removeRepeatedLists(List<List<V>> listOfLists) {
List<List<V>> inputListOfLists = new ArrayList<List<V>>(listOfLists);
List<List<V>> outputListOfLists = new ArrayList<List<V>>();
while(!inputListOfLists.isEmpty()) {
// get the first element
List<V> thisList = inputListOfLists.get(0);
// remove it
inputListOfLists.remove(0);
outputListOfLists.add(thisList);
// look for duplicates
Integer nEl = thisList.size();
Iterator<List<V>> listIt = inputListOfLists.iterator();
while(listIt.hasNext()) {
List<V> remainingList = listIt.next();
if(remainingList.size() == nEl) {
if(remainingList.containsAll(thisList)) {
listIt.remove();
}
}
}
}
return outputListOfLists;
}
}
I'm answering this on the basis that you want to find chordless cycles, but it can be modified to find cycles with chords.
This problem reduces to finding all (inclusion) minimal paths between two vertices s and t.
For all triplets, (v,s,t):
Either v,s,t form a triangle, in which case, output it and continue to next triplet.
Otherwise, remove v and its neighbor except s and t, and enumerate all s-t-paths.
Finding all s-t-paths can be done by dynamic programming.
The input to the program is the set of edges in the graph. For e.g. consider the following simple directed graph:
a -> b -> c
The set of edges for this graph is
{ (b, c), (a, b) }
So given a directed graph as a set of edges, how do you determine if the directed graph is a tree? If it is a tree, what is the root node of the tree?
First of I'm looking at how will you represent this graph, adjacency list/ adjacency matrix / any thing else? How will utilize the representation that you have chosen to efficiently answer the above questions?
Edit 1:
Some people are mentoning about using DFS for cycle detection but the problem is which node to start the DFS from. Since it is a directed graph we cannot start the DFS from a random node, for e.g. if I started a DFS from vertex 'c' it won't proceed further since there is no back edge to go to any other nodes. The follow up question here should be how do you determine what is the root of this tree.
Here's a fairly direct method. It can be done with either an adjacency matrix or an edge list.
Find the set, R, of nodes that do not appear as the destination of any edge. If R does not have exactly one member, the graph is not a tree.
If R does have exactly one member, r, it is the only possible root.
Mark r.
Starting from r, recursively mark all nodes that can be reached by following edges from source to destination. If any node is already marked, there is a cycle and the graph is not a tree. (This step is the same as a previously posted answer).
If any node is not marked at the end of step 3, the graph is not a tree.
If none of those steps find that the graph is not a tree, the graph is a tree with r as root.
It's difficult to know what is going to be efficient without some information about the numbers of nodes and edges.
There are 3 properties to check if a graph is a tree:
(1) The number of edges in the graph is exactly one less than the number of vertices |E| = |V| - 1
(2) There are no cycles
(3) The graph is connected
I think this example algorithm can work in the cases of a directed graph:
# given a graph and a starting vertex, check if the graph is a tree
def checkTree(G, v):
# |E| = |V| - 1
if edges.size != vertices.size - 1:
return false;
for v in vertices:
visited[v] = false;
hasCycle = explore_and_check_cycles(G, v);
# a tree is acyclic
if hasCycle:
return false;
for v in vertices:
if not visited[v]: # the graph isn't connected
return false;
# otherwise passes all properties for a tree
return true;
# given a Graph and a vertex, explore all reachable vertices from the vertex
# and returns true if there are any cycles
def explore_and_check_cycles(G, v):
visited[v] = true;
for (v, u) in edges:
if not visited[u]:
return explore_and_check_cyles(G, u)
else: # a backedge between two vertices indicates a cycle
return true
return false
Sources:
Algorithms by S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani
http://www.cs.berkeley.edu/~vazirani/algorithms.html
start from the root, "mark" it and then go to all children and repeat recursively. if you reach a child that is already marked it means that it is not a tree...
Note: By no means the most efficient way, but conceptually useful. Sometimes you want efficiency, sometimes you want an alternate viewpoint for pedagogic reasons. This is most certainly the later.
Algorithm: Starting with an adjacency matrix A of size n. Take the matrix power A**n. If the matrix is zero for every entry you know that it is at least a collection of trees (a forest). If you can show that it is connected, then it must be a tree. See a Nilpotent matrix. for more information.
To find the root node, we assume that you've shown the graph is a connected tree. Let k be the the number of times you have to raise the power A**k before the matrix becomes all zero. Take the transpose to the (k-1) power A.T ** (k-1). The only non-zero entry must be the root.
Analysis: A rough worse case analysis shows that it is bounded above by O(n^4), three for the matrix multiplication at most n times. You can do better by diagonalizing the matrix which should bring it down to O(n^3). Considering that this problem can be done in O(n), O(1) time/space this is only a useful exercise in logic and understanding of the problem.
For a directed graph, the underlying undirected graph will be a tree if the undirected graph is acyclic and fully connected. The same property holds good if for the directed graph, each vertex has in-degree=1 except one having in-degree=0.
If adjacency-list representation also supports in-degree property of each vertex, then we can apply the above rule easily. Otherwise, we should apply a tweaked DFS to find no-loops for underlying undirected graph as well as that |E|=|V|-1.
Following is the code I have written for this. Feel free to suggest optimisations.
import java.util.*;
import java.lang.*;
import java.io.*;
class Graph
{
private static int V;
private static int adj[][];
static void initializeGraph(int n)
{
V=n+1;
adj = new int[V][V];
for(int i=0;i<V;i++)
{
for(int j=0;j<V ;j++)
adj[i][j]= 0;
}
}
static int isTree(int edges[][],int n)
{
initializeGraph(n);
for(int i=0;i< edges.length;i++)
{
addDirectedEdge(edges[i][0],edges[i][1]);
}
int root = findRoot();
if(root == -1)
return -1;
boolean visited[] = new boolean[V];
boolean isTree = isTree(root, visited, -1);
boolean isConnected = isConnected(visited);
System.out.println("isTree= "+ isTree + " isConnected= "+ isConnected);
if(isTree && isConnected)
return root;
else
return -1;
}
static boolean isTree(int node, boolean visited[], int parent)
{
// System.out.println("node =" +node +" parent" +parent);
visited[node] = true;int j;
for(j =1;j<V;j++)
{
// System.out.println("node =" +node + " j=" +j+ "parent" + parent);
if(adj[node][j]==1)
{
if(visited[j])
{
// System.out.println("returning false for j="+ j);
return false;
}
else
{ //visit all adjacent vertices
boolean child = isTree(j, visited, node);
if(!child)
{
// System.out.println("returning false for j="+ j + " node=" +node);
return false;
}
}
}
}
if(j==V)
return true;
else
return false;
}
static int findRoot()
{
int root =-1, j=0,i;
int count =0;
for(j=1;j<V ;j++)
{
count=0;
for(i=1 ;i<V;i++)
{
if(adj[i][j]==1)
count++;
}
// System.out.println("j"+j +" count="+count);
if(count==0)
{
// System.out.println(j);
return j;
}
}
return -1;
}
static void addDirectedEdge(int s, int d)
{
// System.out.println("s="+ s+"d="+d);
adj[s][d]=1;
}
static boolean isConnected(boolean visited[])
{
for(int i=1; i<V;i++)
{
if(!visited[i])
return false;
}
return true;
}
public static void main (String[] args) throws java.lang.Exception
{
int edges[][]= {{2,3},{2,4},{3,1},{3,5},{3,7},{4,6}, {2,8}, {8,9}};
int n=9;
int root = isTree(edges,n);
System.out.println("root is:" + root);
int edges2[][]= {{2,3},{2,4},{3,1},{3,5},{3,7},{4,6}, {2,8}, {6,3}};
int n2=8;
root = isTree(edges2,n2);
System.out.println("root is:" + root);
}
}
I am working on an implementation of Dijkstra's Algorithm to retrieve the shortest path between interconnected nodes on a network of routes. I have the implementation working. It returns all the shortest paths to all the nodes when I pass the start node into the algorithm.
My question:
How does one go about retrieving all possible paths from Node A to, say, Node G or even all possible paths from Node A and back to Node A?
Finding all possible paths is a hard problem, since there are exponential number of simple paths. Even finding the kth shortest path [or longest path] are NP-Hard.
One possible solution to find all paths [or all paths up to a certain length] from s to t is BFS, without keeping a visited set, or for the weighted version - you might want to use uniform cost search
Note that also in every graph which has cycles [it is not a DAG] there might be infinite number of paths between s to t.
I've implemented a version where it basically finds all possible paths from one node to the other, but it doesn't count any possible 'cycles' (the graph I'm using is cyclical). So basically, no one node will appear twice within the same path. And if the graph were acyclical, then I suppose you could say it seems to find all the possible paths between the two nodes. It seems to be working just fine, and for my graph size of ~150, it runs almost instantly on my machine, though I'm sure the running time must be something like exponential and so it'll start to get slow quickly as the graph gets bigger.
Here is some Java code that demonstrates what I'd implemented. I'm sure there must be more efficient or elegant ways to do it as well.
Stack connectionPath = new Stack();
List<Stack> connectionPaths = new ArrayList<>();
// Push to connectionsPath the object that would be passed as the parameter 'node' into the method below
void findAllPaths(Object node, Object targetNode) {
for (Object nextNode : nextNodes(node)) {
if (nextNode.equals(targetNode)) {
Stack temp = new Stack();
for (Object node1 : connectionPath)
temp.add(node1);
connectionPaths.add(temp);
} else if (!connectionPath.contains(nextNode)) {
connectionPath.push(nextNode);
findAllPaths(nextNode, targetNode);
connectionPath.pop();
}
}
}
I'm gonna give you a (somewhat small) version (although comprehensible, I think) of a scientific proof that you cannot do this under a feasible amount of time.
What I'm gonna prove is that the time complexity to enumerate all simple paths between two selected and distinct nodes (say, s and t) in an arbitrary graph G is not polynomial. Notice that, as we only care about the amount of paths between these nodes, the edge costs are unimportant.
Sure that, if the graph has some well selected properties, this can be easy. I'm considering the general case though.
Suppose that we have a polynomial algorithm that lists all simple paths between s and t.
If G is connected, the list is nonempty. If G is not and s and t are in different components, it's really easy to list all paths between them, because there are none! If they are in the same component, we can pretend that the whole graph consists only of that component. So let's assume G is indeed connected.
The number of listed paths must then be polynomial, otherwise the algorithm couldn't return me them all. If it enumerates all of them, it must give me the longest one, so it is in there. Having the list of paths, a simple procedure may be applied to point me which is this longest path.
We can show (although I can't think of a cohesive way to say it) that this longest path has to traverse all vertices of G. Thus, we have just found a Hamiltonian Path with a polynomial procedure! But this is a well known NP-hard problem.
We can then conclude that this polynomial algorithm we thought we had is very unlikely to exist, unless P = NP.
The following functions (modified BFS with a recursive path-finding function between two nodes) will do the job for an acyclic graph:
from collections import defaultdict
# modified BFS
def find_all_parents(G, s):
Q = [s]
parents = defaultdict(set)
while len(Q) != 0:
v = Q[0]
Q.pop(0)
for w in G.get(v, []):
parents[w].add(v)
Q.append(w)
return parents
# recursive path-finding function (assumes that there exists a path in G from a to b)
def find_all_paths(parents, a, b):
return [a] if a == b else [y + b for x in list(parents[b]) for y in find_all_paths(parents, a, x)]
For example, with the following graph (DAG) G given by
G = {'A':['B','C'], 'B':['D'], 'C':['D', 'F'], 'D':['E', 'F'], 'E':['F']}
if we want to find all paths between the nodes 'A' and 'F' (using the above-defined functions as find_all_paths(find_all_parents(G, 'A'), 'A', 'F')), it will return the following paths:
Here is an algorithm finding and printing all paths from s to t using modification of DFS. Also dynamic programming can be used to find the count of all possible paths. The pseudo code will look like this:
AllPaths(G(V,E),s,t)
C[1...n] //array of integers for storing path count from 's' to i
TopologicallySort(G(V,E)) //here suppose 's' is at i0 and 't' is at i1 index
for i<-0 to n
if i<i0
C[i]<-0 //there is no path from vertex ordered on the left from 's' after the topological sort
if i==i0
C[i]<-1
for j<-0 to Adj(i)
C[i]<- C[i]+C[j]
return C[i1]
If you actually care about ordering your paths from shortest path to longest path then it would be far better to use a modified A* or Dijkstra Algorithm. With a slight modification the algorithm will return as many of the possible paths as you want in order of shortest path first. So if what you really want are all possible paths ordered from shortest to longest then this is the way to go.
If you want an A* based implementation capable of returning all paths ordered from the shortest to the longest, the following will accomplish that. It has several advantages. First off it is efficient at sorting from shortest to longest. Also it computes each additional path only when needed, so if you stop early because you dont need every single path you save some processing time. It also reuses data for subsequent paths each time it calculates the next path so it is more efficient. Finally if you find some desired path you can abort early saving some computation time. Overall this should be the most efficient algorithm if you care about sorting by path length.
import java.util.*;
public class AstarSearch {
private final Map<Integer, Set<Neighbor>> adjacency;
private final int destination;
private final NavigableSet<Step> pending = new TreeSet<>();
public AstarSearch(Map<Integer, Set<Neighbor>> adjacency, int source, int destination) {
this.adjacency = adjacency;
this.destination = destination;
this.pending.add(new Step(source, null, 0));
}
public List<Integer> nextShortestPath() {
Step current = this.pending.pollFirst();
while( current != null) {
if( current.getId() == this.destination )
return current.generatePath();
for (Neighbor neighbor : this.adjacency.get(current.id)) {
if(!current.seen(neighbor.getId())) {
final Step nextStep = new Step(neighbor.getId(), current, current.cost + neighbor.cost + predictCost(neighbor.id, this.destination));
this.pending.add(nextStep);
}
}
current = this.pending.pollFirst();
}
return null;
}
protected int predictCost(int source, int destination) {
return 0; //Behaves identical to Dijkstra's algorithm, override to make it A*
}
private static class Step implements Comparable<Step> {
final int id;
final Step parent;
final int cost;
public Step(int id, Step parent, int cost) {
this.id = id;
this.parent = parent;
this.cost = cost;
}
public int getId() {
return id;
}
public Step getParent() {
return parent;
}
public int getCost() {
return cost;
}
public boolean seen(int node) {
if(this.id == node)
return true;
else if(parent == null)
return false;
else
return this.parent.seen(node);
}
public List<Integer> generatePath() {
final List<Integer> path;
if(this.parent != null)
path = this.parent.generatePath();
else
path = new ArrayList<>();
path.add(this.id);
return path;
}
#Override
public int compareTo(Step step) {
if(step == null)
return 1;
if( this.cost != step.cost)
return Integer.compare(this.cost, step.cost);
if( this.id != step.id )
return Integer.compare(this.id, step.id);
if( this.parent != null )
this.parent.compareTo(step.parent);
if(step.parent == null)
return 0;
return -1;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Step step = (Step) o;
return id == step.id &&
cost == step.cost &&
Objects.equals(parent, step.parent);
}
#Override
public int hashCode() {
return Objects.hash(id, parent, cost);
}
}
/*******************************************************
* Everything below here just sets up your adjacency *
* It will just be helpful for you to be able to test *
* It isnt part of the actual A* search algorithm *
********************************************************/
private static class Neighbor {
final int id;
final int cost;
public Neighbor(int id, int cost) {
this.id = id;
this.cost = cost;
}
public int getId() {
return id;
}
public int getCost() {
return cost;
}
}
public static void main(String[] args) {
final Map<Integer, Set<Neighbor>> adjacency = createAdjacency();
final AstarSearch search = new AstarSearch(adjacency, 1, 4);
System.out.println("printing all paths from shortest to longest...");
List<Integer> path = search.nextShortestPath();
while(path != null) {
System.out.println(path);
path = search.nextShortestPath();
}
}
private static Map<Integer, Set<Neighbor>> createAdjacency() {
final Map<Integer, Set<Neighbor>> adjacency = new HashMap<>();
//This sets up the adjacencies. In this case all adjacencies have a cost of 1, but they dont need to.
addAdjacency(adjacency, 1,2,1,5,1); //{1 | 2,5}
addAdjacency(adjacency, 2,1,1,3,1,4,1,5,1); //{2 | 1,3,4,5}
addAdjacency(adjacency, 3,2,1,5,1); //{3 | 2,5}
addAdjacency(adjacency, 4,2,1); //{4 | 2}
addAdjacency(adjacency, 5,1,1,2,1,3,1); //{5 | 1,2,3}
return Collections.unmodifiableMap(adjacency);
}
private static void addAdjacency(Map<Integer, Set<Neighbor>> adjacency, int source, Integer... dests) {
if( dests.length % 2 != 0)
throw new IllegalArgumentException("dests must have an equal number of arguments, each pair is the id and cost for that traversal");
final Set<Neighbor> destinations = new HashSet<>();
for(int i = 0; i < dests.length; i+=2)
destinations.add(new Neighbor(dests[i], dests[i+1]));
adjacency.put(source, Collections.unmodifiableSet(destinations));
}
}
The output from the above code is the following:
[1, 2, 4]
[1, 5, 2, 4]
[1, 5, 3, 2, 4]
Notice that each time you call nextShortestPath() it generates the next shortest path for you on demand. It only calculates the extra steps needed and doesnt traverse any old paths twice. Moreover if you decide you dont need all the paths and end execution early you've saved yourself considerable computation time. You only compute up to the number of paths you need and no more.
Finally it should be noted that the A* and Dijkstra algorithms do have some minor limitations, though I dont think it would effect you. Namely it will not work right on a graph that has negative weights.
Here is a link to JDoodle where you can run the code yourself in the browser and see it working. You can also change around the graph to show it works on other graphs as well: http://jdoodle.com/a/ukx
find_paths[s, t, d, k]
This question is now a bit old... but I'll throw my hat into the ring.
I personally find an algorithm of the form find_paths[s, t, d, k] useful, where:
s is the starting node
t is the target node
d is the maximum depth to search
k is the number of paths to find
Using your programming language's form of infinity for d and k will give you all paths§.
§ obviously if you are using a directed graph and you want all undirected paths between s and t you will have to run this both ways:
find_paths[s, t, d, k] <join> find_paths[t, s, d, k]
Helper Function
I personally like recursion, although it can difficult some times, anyway first lets define our helper function:
def find_paths_recursion(graph, current, goal, current_depth, max_depth, num_paths, current_path, paths_found)
current_path.append(current)
if current_depth > max_depth:
return
if current == goal:
if len(paths_found) <= number_of_paths_to_find:
paths_found.append(copy(current_path))
current_path.pop()
return
else:
for successor in graph[current]:
self.find_paths_recursion(graph, successor, goal, current_depth + 1, max_depth, num_paths, current_path, paths_found)
current_path.pop()
Main Function
With that out of the way, the core function is trivial:
def find_paths[s, t, d, k]:
paths_found = [] # PASSING THIS BY REFERENCE
find_paths_recursion(s, t, 0, d, k, [], paths_found)
First, lets notice a few thing:
the above pseudo-code is a mash-up of languages - but most strongly resembling python (since I was just coding in it). A strict copy-paste will not work.
[] is an uninitialized list, replace this with the equivalent for your programming language of choice
paths_found is passed by reference. It is clear that the recursion function doesn't return anything. Handle this appropriately.
here graph is assuming some form of hashed structure. There are a plethora of ways to implement a graph. Either way, graph[vertex] gets you a list of adjacent vertices in a directed graph - adjust accordingly.
this assumes you have pre-processed to remove "buckles" (self-loops), cycles and multi-edges
You usually don't want to, because there is an exponential number of them in nontrivial graphs; if you really want to get all (simple) paths, or all (simple) cycles, you just find one (by walking the graph), then backtrack to another.
I think what you want is some form of the Ford–Fulkerson algorithm which is based on BFS. Its used to calculate the max flow of a network, by finding all augmenting paths between two nodes.
http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
There's a nice article which may answer your question /only it prints the paths instead of collecting them/.
Please note that you can experiment with the C++/Python samples in the online IDE.
http://www.geeksforgeeks.org/find-paths-given-source-destination/
I suppose you want to find 'simple' paths (a path is simple if no node appears in it more than once, except maybe the 1st and the last one).
Since the problem is NP-hard, you might want to do a variant of depth-first search.
Basically, generate all possible paths from A and check whether they end up in G.
How to find all chordless cycles in an undirected graph?
For example, given the graph
0 --- 1
| | \
| | \
4 --- 3 - 2
the algorithm should return 1-2-3 and 0-1-3-4, but never 0-1-2-3-4.
(Note: [1] This question is not the same as small cycle finding in a planar graph because the graph is not necessarily planar. [2] I have read the paper Generating all cycles, chordless cycles, and Hamiltonian cycles with the principle of exclusion but I don't understand what they're doing :). [3] I have tried CYPATH but the program only gives the count, algorithm EnumChordlessPath in readme.txt has significant typos, and the C code is a mess. [4] I am not trying to find an arbitrary set of fundametal cycles. Cycle basis can have chords.)
Assign numbers to nodes from 1 to n.
Pick the node number 1. Call it 'A'.
Enumerate pairs of links coming out of 'A'.
Pick one. Let's call the adjacent nodes 'B' and 'C' with B less than C.
If B and C are connected, then output the cycle ABC, return to step 3 and pick a different pair.
If B and C are not connected:
Enumerate all nodes connected to B. Suppose it's connected to D, E, and F. Create a list of vectors CABD, CABE, CABF. For each of these:
if the last node is connected to any internal node except C and B, discard the vector
if the last node is connected to C, output and discard
if it's not connected to either, create a new list of vectors, appending all nodes to which the last node is connected.
Repeat until you run out of vectors.
Repeat steps 3-5 with all pairs.
Remove node 1 and all links that lead to it. Pick the next node and go back to step 2.
Edit: and you can do away with one nested loop.
This seems to work at the first sight, there may be bugs, but you should get the idea:
void chordless_cycles(int* adjacency, int dim)
{
for(int i=0; i<dim-2; i++)
{
for(int j=i+1; j<dim-1; j++)
{
if(!adjacency[i+j*dim])
continue;
list<vector<int> > candidates;
for(int k=j+1; k<dim; k++)
{
if(!adjacency[i+k*dim])
continue;
if(adjacency[j+k*dim])
{
cout << i+1 << " " << j+1 << " " << k+1 << endl;
continue;
}
vector<int> v;
v.resize(3);
v[0]=j;
v[1]=i;
v[2]=k;
candidates.push_back(v);
}
while(!candidates.empty())
{
vector<int> v = candidates.front();
candidates.pop_front();
int k = v.back();
for(int m=i+1; m<dim; m++)
{
if(find(v.begin(), v.end(), m) != v.end())
continue;
if(!adjacency[m+k*dim])
continue;
bool chord = false;
int n;
for(n=1; n<v.size()-1; n++)
if(adjacency[m+v[n]*dim])
chord = true;
if(chord)
continue;
if(adjacency[m+j*dim])
{
for(n=0; n<v.size(); n++)
cout<<v[n]+1<<" ";
cout<<m+1<<endl;
continue;
}
vector<int> w = v;
w.push_back(m);
candidates.push_back(w);
}
}
}
}
}
#aioobe has a point. Just find all the cycles and then exclude the non-chordless ones. This may be too inefficient, but the search space can be pruned along the way to reduce the inefficiencies. Here is a general algorithm:
void printChordlessCycles( ChordlessCycle path) {
System.out.println( path.toString() );
for( Node n : path.lastNode().neighbors() ) {
if( path.canAdd( n) ) {
path.add( n);
printChordlessCycles( path);
path.remove( n);
}
}
}
Graph g = loadGraph(...);
ChordlessCycle p = new ChordlessCycle();
for( Node n : g.getNodes()) {
p.add(n);
printChordlessCycles( p);
p.remove( n);
}
class ChordlessCycle {
private CountedSet<Node> connected_nodes;
private List<Node> path;
...
public void add( Node n) {
for( Node neighbor : n.getNeighbors() ) {
connected_nodes.increment( neighbor);
}
path.add( n);
}
public void remove( Node n) {
for( Node neighbor : n.getNeighbors() ) {
connected_nodes.decrement( neighbor);
}
path.remove( n);
}
public boolean canAdd( Node n) {
return (connected_nodes.getCount( n) == 0);
}
}
Just a thought:
Let's say you are enumerating cycles on your example graph and you are starting from node 0.
If you do a breadth-first search for each given edge, e.g. 0 - 1, you reach a fork at 1. Then the cycles that reach 0 again first are chordless, and the rest are not and can be eliminated... at least I think this is the case.
Could you use an approach like this? Or is there a counterexample?
How about this. First, reduce the problem to finding all chordless cycles that pass through a given vertex A. Once you've found all of those, you can remove A from the graph, and repeat with another point until there's nothing left.
And how to find all the chordless cycles that pass through vertex A? Reduce this to finding all chordless paths from B to A, given a list of permitted vertices, and search either breadth-first or depth-first. Note that when iterating over the vertices reachable (in one step) from B, when you choose one of them you must remove all of the others from the list of permitted vertices (take special care when B=A, so as not to eliminate three-edge paths).
Find all cycles.
Definition of a chordless cycle is a set of points in which a subset cycle of those points don't exist. So, once you have all cycles problem is simply to eliminate cycles which do have a subset cycle.
For efficiency, for each cycle you find, loop through all existing cycles and verify that it is not a subset of another cycle or vice versa, and if so, eliminate the larger cycle.
Beyond that, only difficulty is figuring out how to write an algorithm that determines if a set is a subset of another.