You are given a directed acyclic graph (DAG) and you intend to find all the nodes reachable from a given node. Consider the following recurrence solution, where f(u)
denotes the set of nodes reachable from u.
This simply means that the nodes you can reach from u
is the union of the nodes you can reach from all its out-neighbors (adjacent nodes). This can easily be achieved with DFS (depth-first search) along with memoization of previously computed f(u)
sets. This approach has a time-complexity of O(|E| + |V| + |E||V|log(|V|))
and an additional space-complexity of O(|V|^2)
. Note that this algorithm doesn't scale well to very large graphs due to the |V|^2
memory requirement.
The following C++ code demonstrates this approach :
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
using namespace std;
#define FOR(i,n) for(int i=0;i<n;++i)
#define FORS(i,s,n) for(int i=s;i<n;++i)
#define MAX 1000000
#define WHITE 0
#define GRAY 1
#define BLACK 2
void dfs_visit(vector<int> adj[], int u, int color[], set<int> cache[])
{
color[u]=GRAY;
int len = adj[u].size();
FOR(i,len)
{
int v = adj[u][i];
if(color[v]==WHITE)
{
dfs_visit(adj,v,color,cache);
}
}
// Before coloring a node black, set its f(u) to be the union of the f(v) of its neighbours for all v
FOR(i,len)
{
int v = adj[u][i];
cache[u].insert(v);
// This will take time logarithmic in the size of f(u) since each insertion requires comparison for uniqueness
for(set<int>::iterator it = cache[v].begin(); it!=cache[v].end(); ++it)
{
cache[u].insert(*it);
}
}
color[u]=BLACK;
}
void dfs(vector<int> adj[], set<int> cache[], int n)
{
int color[n];
memset(color, WHITE, sizeof(color));
FOR(i,n)
{
if(color[i]==WHITE)
{
dfs_visit(adj, i, color, cache);
}
}
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
// To handle 0-based index, initialize as n+1
set<int> cache[n+1];
vector<int> adj[n+1];
FOR(i,m)
{
int u,v;
scanf("%d%d", &u, &v);
adj[u].push_back(v);
}
dfs(adj, cache, n);
FORS(i,1,n)
{
set<int> fu = cache[i];
printf("%d->{", i);
for(set<int>::iterator it=fu.begin(); it!=fu.end(); ++it)
{
printf("%d,", *it);
}
printf("}\n");
}
return 0;
}
Input (N=Number of nodes, M=Number of edges, M lines follow with edge list):
5 6
1 3
2 4
3 4
3 2
4 5
Output:
1->{2,3,4,5,}
2->{4,5,}
3->{2,4,5,}
4->{5,}