Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding reachable vertices for every vertex in a directed graph

I know that brute force approach to do this is perform DFS on all the vertices of the graph.So for this algorithm the complexity would be O(V|V+E|). But is there more efficient way to do this?

like image 427
mc20 Avatar asked Apr 25 '15 23:04

mc20


People also ask

How do you count all reachable nodes in a directed graph?

This can be done by first finding Strongly Connected Components (SCC), which can be done in O(|V|+|E|) . Then, build a new graph, G' , for the SCCs (each SCC is a node in the graph), where each node has value which is the sum of the nodes in that SCC.

How do you find all possible paths in a directed graph?

Finding all the possible paths in any graph in Exponential. It can be solved by using Backtracking. For DAG's we can do it using Depth first search(DFS). In DFS code, Start at any node, Go to the extreme dead end path and note down all the nodes visited in that path using some array or list.

Does BFS visit every vertex?

Each vertex, except the source vertex s, has a parent; these edges (v, parent[v]) define a tree, called the BFS-tree. Lemma: On a directed graph, BFS(s) reaches all vertices reachable from s.

How do you find the number of reachable vertices of a graph?

Given a directed graph (not necessarily a DAG), for every vertex v calculate the number of reachable vertices from v. So using brute force approach (n times DFS) we can get the answer in O (n^2) time complexity.

How to find path between two vertices in a directed graph?

Given a Directed Graph and two vertices in it, check whether there is a path from the first given vertex to second. For example, in the following graph, there is a path from vertex 1 to 3. As another example, there is no path from 3 to 0. We can either use Breadth First Search (BFS) or Depth First Search (DFS) to find path between two vertices.

How do you find the mother vertex of a graph?

A mother vertex in a graph G = (V,E) is a vertex v such that all other vertices in G can be reached by a path from v. There can be more than one mother vertices in a graph. We need to output anyone of them. For example, in the below graph, vertices 0, 1 and 2 are mother vertices.

How to check if a vertex is not reachable from the source?

The idea is to start the BFS routine from the source vertex and check if the destination vertex is reached during the traversal. If the destination vertex is not encountered at any point, we can say that it’s not reachable from the source vertex. This approach is demonstrated below in C++, Java, and Python:


3 Answers

I get the impression from papers like http://research.microsoft.com/pubs/144985/todsfinal.pdf that there is no algorithm that does better than O(VE) or O(V^3) in the general case. For sparse graphs and other special graphs there are faster algorithms. It seems, however, that you can still make improvements by separating "index construction" from "query", if you have some idea of the number of queries that will be made on the data. If there are going to be a lot of queries, O(1) is possible for queries if all the data is pre-computed (DFS or Floyd-Warshall, etc.) and stored in O(n^2) space. On the other hand, if there are going to be relatively few queries, space and/or index construction time can be reduced at the expense of query time.

like image 165
Edward Doolittle Avatar answered Oct 03 '22 09:10

Edward Doolittle


I really suspect that there isn't a known better algorithm for general graphs. All the papers I found on the subject [1] [2] describe algorithms that run in O(|V| * |E|) time. That isn't better than your naïve attempt in the worst case.

Even the wikipedia page [3] says the fastest algorithms reduce the problem to matrix multiplication, which the fastest algorithms are only marginally better than your baseline.

[1] http://ion.uwinnipeg.ca/~ychen2/conferencePapers/tranRelationCopy.pdf

[2] http://www.vldb.org/conf/1988/P382.PDF

[3] http://en.wikipedia.org/wiki/Transitive_closure#Algorithms

like image 39
Juan Lopes Avatar answered Oct 04 '22 09:10

Juan Lopes


[EDIT: As pointed out by kraskevich, the final query step can be worse than I had originally claimed: up to O(|V|^2) even for an output of size O(|V|), which is no better than ordinary DFS without any preprocessing.].

In the worst case, O(|V|^2) space would be needed to store all this information explicitly -- i.e., to store the complete list of reachable vertices for each vertex (think of a graph in which every vertex has an edge to every other vertex). But it's possible to represent it in such a way that only O(|V|) space is needed, and this representation can be built in O(|V|+|E|) time, and a query on it will only take time proportional to the size of the answer (number of reachable vertices).

The basic idea is: Every vertex in a strongly connected component (SCC) can reach every other vertex in the same SCC (this is the definition of SCC), and can reach all vertices in SCCs that it can reach, and no other vertices.

  1. Find all SCCs; this can be done in O(|V|+|E|) time. Build a table SCC, so that SCC(u) = i if the SCC of u is i (both vertices in G and SCCs can be represented as integers). Afterwards make another pass through this table to build a dual table, Verts, so that Verts(i) contains a list of all vertices in the ith SCC.
  2. Build a new graph G' whose vertices are the SCCs of G. G' will necessarily be acyclic.

So, given a vertex u in G, look up its SCC, SCC(u). Call this i. Perform a DFS through G' starting at vertex i: For each vertex (of G') j encountered during this DFS, output every vertex (of G) in Verts(j).

like image 38
j_random_hacker Avatar answered Oct 03 '22 09:10

j_random_hacker