Finding the longest path In an unweighted graph - algorithm

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).

Related

Does this BFS-based algorithm work for find shortest path in weighted graph

I know that plain BFS search can be used for find shortest path in unweighted graph or graph with same edge weight, and Dijkstra should be used in weighted graph, and Dijkstra can be seen as a variant of BFS.
But I wonder if I push the node to the queue every time the dist[w] is updated, instead of only push once in plain BFS search, will this algorithm work for finding shortest path? I tried this algorithm on one leetcode problem, and it worked, but the leetcode problem only check limited testcase, so I cant prove the correctness of this algorithm. If the algorithm is correct, what's the time complexity?
vector<int>dist(N + 1, INT_MAX);
dist[start] = 0;
queue<int>q;
q.push(start);
while(!q.empty()){
int v = q.front(); q.pop();
for(auto [w, cost] : g[v]){
// cout<<w<<" "<<cost<<endl;
if(cost + dist[v] < dist[w]){
dist[w] = cost + dist[v];
q.push(w);
}
}
}
I believe you have rediscovered the Bellman-Ford algorithm, minus the necessary handling for failing out on negative weight cycles. It should run in O(|V| * |E|) time (as opposed to the O((|V| + |E|) * lg(|V|)) of Dijkstra's) assuming no negative cycles, which will infinite loop on your implementation. The good part is that it handles negative edge weights, which Dijkstra's does not. The bad part is that it is much slower.
See https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm

Find path with maximum cost difference of edges in directed graph in linear-time

Having a directed graph G with edges having positive weights, we define the cost of a path the difference between the edge with minimum weight and maximum weight. The goal is to find a path with maximum cost among other paths. We don't need to return the path itself just the maximum cost.
If x is the number of vertices and y is the number of edges then x < 10^5 and y < min(x^2,10^5). The time limit is 1 second.
Based on the bounds I think this problem has to be solved in O(x+y) time.
So based on the problems properties ans some studying of other algorithms I thought that on possible answer may contain multiple DFS's (like the SCC problem). I also find a similar problem with Dijkstra's algorithm that can be modified for this problem but I'm not very sure that the complexity would be OK. Also there are some other questions similar to mine however the answers were of O(m^2) or higher which were not very efficient.
Other than what was mentioned above I have no idea to solve the problem and some insight would be very helpful. Thanks
Solution:
Due to the fact that our graph can have cycles, this complicates things for us. Let's build a new graph in which we "compress" all the components of a strong connection into a single vertex, so new graph will be acyclic. During this process let's memorize maximum(maximumWeight[v]) and minimum(minimumWeigh[v]) weights of the edges for each strongly connected components.
We spent O(|V| + |E|) time for it, where |V| is count of vertexes and |E| is count if edges.
After that let's make a topological sorting of given graph in O(|V|+|E|) time complexity. Then let's calculate simple DP.
dpMax[v] - the maximum weight of the edge to which there is a path from this vertex.
dpMin[v] - the minimum weight of the edge to which there is a path from this vertex.
Default value:
If vertex v is strongly connected component, then maximum and minimum weights already calculates in maximumWeight[v] and minimumWeigh[v], so dpMax[v] = maximumWeight[v] and dpMin[v] = minimumWeight[v].
Otherwise maximumWeight[v] = -Infinity and minimumWeigh[v] = Infinity.
In topological order let's improve our DP for each vertex:
int answer = -Infinity;
for(auto v : vertexesInTopologicalOrder) {
int newMinDp = dpMin[v], newMaxDp = dpMax[v];
for(auto e : v.outgoingEdges) {
int l = dpMin[v];
int r = dpMax[v];
l = min(l, e.weight);
r = max(r, e.weight);
l = min(l, dpMin[e.target]);
r = max(r, dpMax[e.target]);
answer = max(answer, e.weight - l);
answer = max(answer, r - e.weight);
newMinDp = min(newMinDp, l);
newMaxDp = max(newMaxDp, r);
}
dpMin[v] = newMinDp;
dpMax[v] = newMaxDp;
}
Since we calculating DP in topological order, the DP at achievable vertexes have already been calculated.
For a better understanding, let's look at an example.
Let's say we have such an initial graph.
After compression, the graph will look something like this.
After topological sorting, we get this order of vertices. (Green numbers)
Sequentially calculate all DP values, along with updating the answer.
Final answer 6 will be achieved during calculating top vertex DP.
I hope it turned out to be quite detailed and clear. Final time complexity is O(|V|+|E|).

DIrected Acyclic Graph shortest path within N steps

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)

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.

Which algorithm can I use to find the next to shortest path in a graph?

I want to find the next shortest path between 2 vertices in a graph and the path has a positive cost.The next shortest path is allowed to share edges of the shortest path .Which algorithm can I use?
Use the K-shortest path algorithm, where k=2 for you, some sample reference:
Finding the k shortest paths.
D. Eppstein.
35th IEEE Symp. Foundations of Comp. Sci., Santa Fe, 1994, pp. 154-165.
Tech. Rep. 94-26, ICS, UCI, 1994.
SIAM J. Computing 28(2):652-673, 1998.
http://www.ics.uci.edu/~eppstein/pubs/Epp-TR-94-26.pdf
I doubt this is optimal in terms of running time but:
Use Dijkstra's algorithm on graph G to get path P
For all edges E in path P:
-- If G - E is not connected, continue for next edge (go to 2)
-- Use Dijkstra's algorithm on G - E to find path X_i
-- If length of current X_i is shorter than all other X_i, save it
The X_i at the end of the for loop is the second shortest path
The second-shortest path can't go through all edges in P, but it could go through all but one of them, potentially. I assume by "second-shortest" that you don't use edges more than once, otherwise the second-shortest path could contain P.
One way is to use Floyd-Warshall's algorithm to find all pairs shortest path and then testing all intermediate edges is a sure - but perhaps not optimal way - to solve this. Here's a great explanation
http://hatemabdelghani.wordpress.com/2009/07/04/second-shortest-path/
This is assuming you can reuse edges and nodes:
A straightfoward solution is do make an extension of the Djikstra Algorithm.
Instead of storing for each node the smallest cost and its respective parent, store the two smallest costs (and their respective parents).
For the priority queue, intead of storing nodes, store (node, i) pairs, so you know wether to use the 1st or 2nd path during propagation.
Take care during the propagation phases to keep the multiple path values correctly updated.
(I might be missing some important details but the basic idea is here...)
Use the shortest path algorithm to find the shortest path, P.
You then can view this problem as a constraint satisfaction problem (where the constraint is "the shortest path which is not P") and, use a backtracking algorithm to find the shortest path which is not the shortest path you already found.
This answer assumes you are looking for the edge-disjoint second shortest path, which means the second shortest path cannot share any common edges with the shortest path.
Recall that the maximum flow in a network between two nodes A and B gives you the number of edge-disjoint paths between those two nodes. Also recall that algorithms such as Edmonds-Karp work by sending flow over a shortest path at each step.
So this problem only has a solution if the max flow between your two nodes is > 1, where each edge has a capacity of 1. If it does, find two augmenting paths as described in the Edmonds-Karp algorithm, and the second one is your second shortest.
See this problem and this solution to it (The description is in Chinese. I can't translate it, and babelfish can't really do it either, but won't admit it. The code is easy to follow though) for an example.
When you prefer a practical solution to an academic one, here is one.
I solved this by setting a penalty to the shortest path edges and running the search again.
E.g. shortest path has length 1000, penalty is 10%, so I search for a 2nd shortest path with 1000<=length<=1100.
In the worst case I find the previous shortest path.
In the best case I find a disjunct path with the same length.
In most cases I find a path sharing some locally optimal subpaths.
Increasing the penalty forces the algorithm to find alternative routes, while decreasing makes it sharing tolerant.
When I find the 2nd shortest path, I have to subtract the sum of penalties on shared edges from the computed length to get the real length.
For k-th shortest path I set the penalty to all edges used in previous k-1 shortest paths.
You're looking for k shortest path routing. Basically, run modified Dijkstra, but instead of keeping edges on the min-heap, keep all paths found so far.
I prefer working code since the devil is always in the detail:
#SuppressWarnings("unchecked")
public static Iterable<Integer>[] kShortestPaths(EdgeWeightedDigraph g, int s, int t, int k) {
if (k <= 0) throw new IllegalArgumentException("k must be positive");
boolean[] visited = new boolean[g.V()];
int[] count = new int[g.V()];
MinPQ<Map.Entry<Map.Entry<Integer, Double>, Queue<Integer>>> heap = new MinPQ<>(
comparingDouble(e -> e.getKey().getValue())
);
Queue<Integer>[] p = (Queue<Integer>[]) new Queue<?>[k];
heap.insert(new SimpleImmutableEntry<>(new SimpleImmutableEntry<>(s, 0.0d), new Queue<>()));
int i = 0;
while (!heap.isEmpty()) {
Map.Entry<Map.Entry<Integer, Double>, Queue<Integer>> node = heap.delMin();
Integer u = node.getKey().getKey();
if (count[u] >= k) break;
Queue<Integer> pathU = node.getValue();
visited[u] = true;
pathU.enqueue(u);
if (u == t) {
p[i] = new Queue<>();
for (int w : pathU) {
p[i].enqueue(w);
}
i++;
}
if (count[u]++ <= k) {
double costU = node.getKey().getValue();
for (DirectedEdge e : g.adj(u)) {
int v = e.to();
if (!visited[v]) {
Queue<Integer> pathV = new Queue<>();
for (int w : pathU) {
pathV.enqueue(w);
}
heap.insert(new SimpleImmutableEntry<>(new SimpleImmutableEntry<>(v, e.weight() + costU), pathV));
}
}
}
}
return p;
}
EdgeWeightedDigraph and MinPQ are from https://github.com/kevin-wayne/algs4.
k = 1, p = [0, 1, 2, 3]
k = 2, p = [0, 4, 5, 3]

Resources