DIrected Acyclic Graph shortest path within N steps - algorithm

I have a problem of finding a shortest path in positively weighted Directed Acyclic Graph, but with the restriction of maximum number of N steps(edges in the path). It is assumed that the path exists. Additional property of the graph is that if the edge (i, j) is in the graph, then any edge (i, k) is also in the graph for i < k < j. I'm only interested in shortest path between start and end of the graph (after topological sorting).
I know that there is an efficient algorithm for the shortest path in Directed Acyclic Graph in O(V+E) but it doesn't account for the steps limit. I can't think of any way to make it O((V+E)*N), but this would be ideal performance, as it should be good enough to handle graphs of 1000 nodes and 100 steps.
For example consider the following
graph.
The problem is to find the shortest path using at most k=3 steps (edges). The answer is 6 (path 1->4->5->6).

It is actually O(N + M) where N is the number of vertices and M is the number of edges.
You can find more information here: http://www.geeksforgeeks.org/shortest-path-for-directed-acyclic-graphs/
Finding the path (I'm using the code from geeksforgeeks):
Instead of int dist[V] use pair<int, int> dist[V]. Initially dist[S] = {0, -1}. So in this condition if (dist[i->getV()].first > dist[u].first + i->getWeight()) you need to set parent as dist[i->getV()] = {dist[u].first + i->getWeight(), u}.
Then use this recursive code to restore the path:
void restore(int v) {
if(dist[v].second == -1) return;
else answer.push_back(v);
if(v == START_POINT) return;
restore(dist[v].second);
}
Call it with restore(FINAL_POINT)

Related

Finding the longest path In an unweighted graph

i'm having a really tough time with this issue.
If I have a graphh, directed or undirected, unweighted and no cycles. How do I find the longest path?
Many algorithms I have seen rely on the graph being weighted, and reverse the weights and use bellman ford.
I ahve also seen dynamic programming solutions, but here people were simply looking for any path, I'm looking for one from s-t.
Ive been trying to break down the graph into subproblems, where I add one node a a time and give it a value of the parent that it is coming from plus one, but I just canoot get the logic right
can anyone provide an algorithm, exponential time would do, pseudopolynomial would be fantastic?
If the graph can be directed or undirected lets reduce the problem only to directed graphs. If it's undirected then you should make edges from v -> w and from w -> v. You can use modified DFS to measure the longest path starting from the node you pass to this function.
Then run this function to every node and get the maximum value.
Pseudocode for DFS:
DFS(Node v):
if (v.visited?) return 0;
v.visited = true;
longestPath = 0;
foreach(Node n : v.neighbours):
longestPath = max(longestPath, DFS(n) + 1)
return longestPath
Pseudocode for the problem:
longestPath(Node[] verticies):
longestPath = 0
foreach(Node v : vertices):
foreach(Node w: vertices):
w.visited = false;
longestPath = max(longestPath, DFS(v))
return longestPath;
It works in O(n^2) but I think this solution is straight forward.
Just to let you know, there is a solution which works O(n).

Intuition behind the algorithm to compute single source shortest path for every vertex in DAG

The algorithm is as follows:
The algorithm starts by topologically sorting the dag (see Section 22.4) to impose a linear ordering on the vertices. If the dag contains a path from vertex u to vertex v, then u precedes v in the topological sort. We make just one pass over the vertices in the topologically sorted order. As we process each vertex, we relax each edge that leaves the vertex.
Can somebody tell me the intuition behind it? And using that intuition please tell how do we find longest path just be negating the edge weights and running the algorithm
We cannot use Dijkstra's algorithm as edges are allowed to have negative weights.
Finding the shortest path to a vertex is easy if you already know the shortest paths to all the vertices that can precede it. Finding the longest path to a vertex in DAG is easy if you already know the longest path to all the vertices that can precede it.
Processing the vertices in topological order ensures that by the time you get to a vertex, you've already processed all the vertices that can precede it.
Dijkstra's algorithm is necessary for graphs that can contain cycles, because they can't be topologically sorted.
Your question is related to single-source shortest-path problem (SSSP) in DAG.
Topological sorting of a graph represents a linear ordering of the graph. It is allowed to process all vertices in topological order (from left to right), and all shortest paths will be found using relaxation property. Running time of the algorithm is O(|V| + |E|), where V is a set of vertices, E is a set of edges.
If you want to find the longest path (or the critical path) there are the next variants:
First way is to negate the edge weights. The path with the smallest negative value will give the longest path (but for algorithm it will still the smallest path). We can do it because topological sorting may work with negative edge weights.
Second way is to change the relaxation step:
1. Cost of each vertex is initialized to negative infinity
2. Change the relaxation step:
if d(v) < d(u) + w
then d(v) = d(u) + w
else d(v) is remains unchanged
where d - the distance;
u, v - vertices;
w - weight on edge (u, v).
In general case for solving SSSP problem there are Dijkstra's and Bellman-Ford algorithm. The main difference consists in the fact that Bellman-Ford algorithm computes SSSP for any weights in the graph and can detect negative weight cycles in the graph, but Dijkstra's algorithm can work with positive weights.
For more details see Shortest Paths.
Topological sort ensures that we are picking up nodes that come first while travelling from the source, this, in turn, will ensure that every node will have at least one condition that it can be reached from the source.
for (int i = 0; i < N; i++)
if (visited[i] == false)
topologicalSortUtil(i, visited, stack, adj);
for (int i = 0; i < N; i++)
dist[i] = Integer.MAX_VALUE;
dist[s] = 0;
while (stack.empty() == false)
{
int node = (int)stack.pop();
if (dist[node] != Integer.MAX_VALUE)
{
enter code here for(Pair it: adj.get(node)) {
if(dist[node] + it.getWeight() < dist[it.getV()]) {
dist[it.getV()] = dist[node] + it.getWeight();
}
}
}
}
As we are setting dist[src] = 0, it will start from there, the condition dis[node] != infinity will not let any other node than src enter that condition first. Because of topological sort notes coming before src will be discarded.

Bellman Ford Algorithm Explanation

I read the Bellman Ford Algorithm. What I couldn't understand is why is there a loop which runs for |V|-1 times (the upper loop in the following segment).
for ( i = 1; i <= V-1; i++)
{
for (j = 0; j < E; j++)
{
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
{
dist[v] = dist[u] + weight;
}
}
I went through several tutorials. All are saying the same thing that There can be maximum |V| – 1 edges in any simple path, that is why the outer loop runs |v| – 1 times. The idea is, assuming that there is no negative weight cycle, if we have calculated shortest paths with at most i edges, then an iteration over all edges guarantees to give shortest path with at-most (i+1) edges.
So, when i=1, the distances I calculated after the relaxation method, are those the shortest distances from the source ?
Please explain this...
Bellman--Ford has two relevant invariants that hold for all vertices u.
There exists a path from the source to u of length dist[u] (unless dist[u] is INT_MAX).
After i iterations of the outer loop, for all paths from the source to u with i or fewer edges, the length of that path is no less than dist[u].
After V-1 iterations, the second invariant implies that no simple path from the source to u is shorter than dist[u]. The first hence implies that the path that we found is shortest.
Bellman ford vs Dijkstra
Bellman also work for negative weighted graph while Dijkstra work only for positive weighted graph.
Bellman has TC O(V*E) which is greater than the TC of Dijkstra i.e. O(V+E).
Steps of Bellman ford:-
Firstly we initialize an distance array with very large default value.
the array value of source is set to 0.
First try to find the shortest path in first iteration.
Now, again traverse all node and try to do the same as we did in 3rd step if we again we find new shortest path then negative cycle is present.
The idea of step 4 is, step 3 guarantees the shortest distances if the graph doesn’t contain a negative weight cycle. If we iterate through all edges one more time and get a shorter path for any vertex, then there is a negative weight cycle.

Finding all shortest paths from source to all vertices in a digraph

We are given a directed graph G (possibly with cycles) with positive edge weights, and the minimum distance D[v] to every vertex v from a source s is also given (D is an array this way).
The problem is to find the array N[v] = number of paths of length D[v] from s to v,
in linear time.
Now this is a homework problem that I've been struggling with for quite long. I was working along the following thought : I'm trying to remove the cycles by suitably choosing an acyclic subgraph of G, and then try to find shortest paths from s to v in the subgraph.
But I cannot figure out explicitly what to do, so I'd appreciate any help, as in a qualitative idea on what to do.
You can use dynamic programming approach in here, and fill up the number of paths as you go, if D[u] + w(u,v) = D[v], something like:
N = [0,...,0]
N[s] = 1 //empty path
For each vertex v, in *ascending* order of `D[v]`:
for each edge (u,v) such that D[u] < D[v]:
if D[u] + w(u,v) = D[v]: //just found new shortest paths, using (u,v)!
N[v] += N[u]
Complexity is O(VlogV + E), assuming the graph is not sparsed, O(E) is dominanting.
Explanation:
If there is a shortest path v0->v1->...->v_(k-1)->v_k from v0 to v_k, then v0->...->v_(k-1) is a shortest path from v0 to v_k-1, thus - when iterating v_k - N[v_(k-1)] was already computed fully (remember, all edges have positive weights, and D[V_k-1] < D[v_k], and we are iterating by increasing value of D[v]).
Therefor, the path v0->...->v_(k-1) is counted in the number N[V_(k-1)] at this point.
Since v0->...->v_(k-1)-v_k is a shortest path - it means D[v_(k-1)] + w(v_k-1,v_k) = D[v_k] - thus the condition will hold, and we will add the count of this path to N[v_k].
Note that the proof for this algorithm will basically be induction that will follow the guidelines from this explanation more formally.

Count paths with Topological Sort

I have a DAG and I need to count all the paths since any node to another node, I've researched a little bit and I found that it could be done with some Topological Order, but so far the solutions are incomplete or wrong.
So how is the correct way to do it?.
Thanks.
As this is a DAG you can topologically sort the nodes in O(V+E) time. Let's assume the source vertex is S. Then from S start traversing the nodes in depth first fashion. When we're processing node U , let's assume there's an edge U->V then V is of course not yet visited (why? because it's an directed acyclic graph) So you can reach from S to V via node U in d[U] ways where d[U] is the number of paths from S to U.
So number of paths from S to any node V, d[V] = d[x1]+d[x2]+d[x3]+ . . . +d[xy], where there are edge like x1->V, x2->V, . . . xy->V
This algorithm will take O(V+E) to topologically sort the graph and then for calculating number of paths at most O(V*E ). You can further reduce its run time of calculating number of path to O(V+E) using adjacency list instead of adjacency matrix and this is the most efficient solution so far.
You can use recursion to count all of the paths in a tree/DAG. Here is the pseudocode:
function numPaths(node1, node2):
// base case, one path from node to itself
if (node1 == node2): return 1
totalPaths = 0
for edge in node1.edges:
nextNode = edge.destinationNode
totalPaths += numPaths(nextNode, node2)
return totalPaths
Edit:
A good dynamic approach to this problem is the Floyd-Warshall algorithm.
Assume G(V,E)
Let d[i][j] = the number of all the paths from i to j
Then d[i][j]= sigma d[next][j] for all (i,next) in E
It seems too slow? Okay. Just memorise it(some guys call it dynamic programming). Like this
memset(d,-1,sizeof(d))// set all of elements of array d to -1 at the very beginning
saya(int i,int j)
{
if (d[i][j]!=-1) return d[i][j];//d[i][j] has been calculated
if (i==j) return d[i][j]=1;//trivival cases
d[i][j]=0;
for e in i.edges
d[i][j]+=saya(e.next,j);
return d[i][j];
}
Now saya(i,j) will return the number of all the paths from i to j.

Resources