DAG Kth shortest path dynamic programming - algorithm

This is not for homework. I am working through a practice test (not graded) in preparation for a final in a couple of weeks. I have no idea where to go with this one.
Let G = (V;E) be a DAG (directed-acyclic-graph) of n vertices and m edges.
Each edge (u; v) of E has a weight w(u; v) that is an arbitrary value (positive, zero, or negative).
Let k be an input positive integer.
A path in G is called a k-link path if the path has no more than k edges. Let s and t be two vertices of G. A k-link shortest path from s to t is defined as a k-link path from s to t that has the minimum total sum of edge weights among all possible k-link s-to-t paths in G.
Design an O(k(m+ n)) time algorithm to compute a k-link shortest path from s to t.
Any help on the algorithm would be greatly appreciated.

Let dp[amount][currentVertex] give us the length of the shortest path in G which starts from s, ends at currentVertex and consists of amount edges.
make all values of dp unset
dp[0][s] = 0
for pathLength in (0, 1, .. k-1) // (1)
for vertex in V
if dp[pathLength][vertex] is set
for each u where (vertex, u) is in E // (2), other vertex of the edge
if dp[pathLength+1][u] is unset or greater than dp[pathLength][vertex] + cost(vertex, u)
set dp[pathLength+1][u] = dp[pathLength][vertex] + cost(vertex, u)
best = dp[k][t]
for pathLength in (0, 1, .. k)
if dp[pathLength][t] < best
best = dp[pathLength][t]
The algorithm above will give you the length of the k-link shortest path from s to t in G. Its time complexity is dominated by the complexity for the loop (1). The loop (1) alone has complecity O(k), while its inner part - (2) simply traverses the graph. If you use an adjacency list, (2) can be implemented in O(n+m). Therefore the overall complexity is O(k*(n+m)).
However, this will give you only the length of the path, and not the path itself. You can modify this algorithm by storing the previous vertex for each value of dp[][]. Thus, whenever you set the value of dp[pathLength+1][u] with the value of dp[pathLength][vertex] + cost(vertex, u) for some variables vertex, u, pathLength you would know that the previous used vertex was vertex. Therefore, you would store it like prev[pathLength+1][u] = vertex.
After that, you can get the path you want like. The idea is to go backwards by using the links you had created in prev:
pLen = pathLength such that dp[pathLength][t] is minimal
curVertex = t
path = [] // empty array
while pLen >= 0
insert curVertex in the beginning of path
curVertex = prev[pLen][curVertex]
pLen = pLen - 1
path is stored the k-link shortest path from s to t in G.

Related

Maximum weighted path between two vertices in a directed acyclic Graph

Love some guidance on this problem:
G is a directed acyclic graph. You want to move from vertex c to vertex z. Some edges reduce your profit and some increase your profit. How do you get from c to z while maximizing your profit. What is the time complexity?
Thanks!
The problem has an optimal substructure. To find the longest path from vertex c to vertex z, we first need to find the longest path from c to all the predecessors of z. Each problem of these is another smaller subproblem (longest path from c to a specific predecessor).
Lets denote the predecessors of z as u1,u2,...,uk and dist[z] to be the longest path from c to z then dist[z]=max(dist[ui]+w(ui,z))..
Here is an illustration with 3 predecessors omitting the edge set weights:
So to find the longest path to z we first need to find the longest path to its predecessors and take the maximum over (their values plus their edges weights to z).
This requires whenever we visit a vertex u, all of u's predecessors must have been analyzed and computed.
So the question is: for any vertex u, how to make sure that once we set dist[u], dist[u] will never be changed later on? Put it in another way: how to make sure that we have considered all paths from c to u before considering any edge originating at u?
Since the graph is acyclic, we can guarantee this condition by finding a topological sort over the graph. topological sort is like a chain of vertices where all edges point left to right. So if we are at vertex vi then we have considered all paths leading to vi and have the final value of dist[vi].
The time complexity: topological sort takes O(V+E). In the worst case where z is a leaf and all other vertices point to it, we will visit all the graph edges which gives O(V+E).
Let f(u) be the maximum profit you can get going from c to u in your DAG. Then you want to compute f(z). This can be easily computed in linear time using dynamic programming/topological sorting.
Initialize f(u) = -infinity for every u other than c, and f(c) = 0. Then, proceed computing the values of f in some topological order of your DAG. Thus, as the order is topological, for every incoming edge of the node being computed, the other endpoints are calculated, so just pick the maximum possible value for this node, i.e. f(u) = max(f(v) + cost(v, u)) for each incoming edge (v, u).
Its better to use Topological Sorting instead of Bellman Ford since its DAG.
Source:- http://www.utdallas.edu/~sizheng/CS4349.d/l-notes.d/L17.pdf
EDIT:-
G is a DAG with negative edges.
Some edges reduce your profit and some increase your profit
Edges - increase profit - positive value
Edges - decrease profit -
negative value
After TS, for each vertex U in TS order - relax each outgoing edge.
dist[] = {-INF, -INF, ….}
dist[c] = 0 // source
for every vertex u in topological order
if (u == z) break; // dest vertex
for every adjacent vertex v of u
if (dist[v] < (dist[u] + weight(u, v))) // < for longest path = max profit
dist[v] = dist[u] + weight(u, v)
ans = dist[z];

All pairs shortest path with varying weights

Imagine you are given a weighted undirected complete graph with n nodes with non-negative weights Cij, where for i = j Cii = 0, and for i != j Cij > 0. Suppose you have to find the maximal shortest path between any two nodes i and j. Here, you can easily use Floyd-Warshall, or use Dijkstra n times, or whatever, and then just to find the maximum among all n^2 shortest paths.
Now assume that Cij are not constant, but rather can take two values, Aij and Bij, where 0 <= Aij <= Bij. We also have Aii = Bii = 0. Assume you also need to find the maximal shortest path, but with the constraint that m edges must take value Bij, and other Aij. And, if m > n^2, then all edges are equal to Bij. But, when finding shortest path i -> p1 -> ... -> pk -> j, you are intesrested in the worst case, in the sense that on that path you need to choose those edges to take value of Bij, such that path value is maximal if you have fixed nodes on its direction.
For example, a if you have path of length four i-k-l-j, and, in optimal solution on that path only one weight is changed to Bij, and other take value of Aij. And let m1 = Bik + Akl + Alj, m2 = Aik + Bkl + Alj, m3 = Aik + Akl + Blj, the value of that path is max{m1, m2, m3}. So, among all paths between i and j, you have to choose one such that maximal value (described as in this example) is minimal (which is a variant of definition of shortest path). And you have to do it for all pairs i and j.
You are not given the constraint how many you need to vary on each path, but rather value of m, a number of weights that should be varied in the complete graph. And the problem is to find the maximum value of the shortest path, as described.
Also, my question is: is this NP-hard problem, or there exists some polynomial solution?

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.

Path finding algorithm on graph considering both nodes and edges

I have an undirected graph. For now, assume that the graph is complete. Each node has a certain value associated with it. All edges have a positive weight.
I want to find a path between any 2 given nodes such that the sum of the values associated with the path nodes is maximum while at the same time the path length is within a given threshold value.
The solution should be "global", meaning that the path obtained should be optimal among all possible paths. I tried a linear programming approach but am not able to formulate it correctly.
Any suggestions or a different method of solving would be of great help.
Thanks!
If you looking for an algorithm in general graph, your problem is NP-Complete, Assume path length threshold is n-1, and each vertex has value 1, If you find the solution for your problem, you can say given graph has Hamiltonian path or not. In fact If your maximized vertex size path has value n, then you have a Hamiltonian path. I think you can use something like Held-Karp relaxation, for finding good solution.
This might not be perfect, but if the threshold value (T) is small enough, there's a simple algorithm that runs in O(n^3 T^2). It's a small modification of Floyd-Warshall.
d = int array with size n x n x (T + 1)
initialize all d[i][j][k] to -infty
for i in nodes:
d[i][i][0] = value[i]
for e:(u, v) in edges:
d[u][v][w(e)] = value[u] + value[v]
for t in 1 .. T
for k in nodes:
for t' in 1..t-1:
for i in nodes:
for j in nodes:
d[i][j][t] = max(d[i][j][t],
d[i][k][t'] + d[k][j][t-t'] - value[k])
The result is the pair (i, j) with the maximum d[i][j][t] for all t in 0..T
EDIT: this assumes that the paths are allowed to be not simple, they can contain cycles.
EDIT2: This also assumes that if a node appears more than once in a path, it will be counted more than once. This is apparently not what OP wanted!
Integer program (this may be a good idea or maybe not):
For each vertex v, let xv be 1 if vertex v is visited and 0 otherwise. For each arc a, let ya be the number of times arc a is used. Let s be the source and t be the destination. The objective is
maximize ∑v value(v) xv .
The constraints are
∑a value(a) ya ≤ threshold
∀v, ∑a has head v ya - ∑a has tail v ya = {-1 if v = s; 1 if v = t; 0 otherwise (conserve flow)
∀v ≠ x, xv ≤ ∑a has head v ya (must enter a vertex to visit)
∀v, xv ≤ 1 (visit each vertex at most once)
∀v ∉ {s, t}, ∀cuts S that separate vertex v from {s, t}, xv ≤ ∑a such that tail(a) ∉ S &wedge; head(a) &in; S ya (benefit only from vertices not on isolated loops).
To solve, do branch and bound with the relaxation values. Unfortunately, the last group of constraints are exponential in number, so when you're solving the relaxed dual, you'll need to generate columns. Typically for connectivity problems, this means using a min-cut algorithm repeatedly to find a cut worth enforcing. Good luck!
If you just add the weight of a node to the weights of its outgoing edges you can forget about the node weights. Then you can use any of the standard algorigthms for the shortest path problem.

Find cycle of shortest length in a directed graph with positive weights

I was asked this question in an interview, but I couldn't come up with any decent solution. So, I told them the naive approach of finding all the cycles then picking the cycle with the least length.
I'm curious to know what is an efficient solution to this problem.
You can easily modify Floyd-Warshall algorithm. (If you're not familiar with graph theory at all, I suggest checking it out, e.g. getting a copy of Introduction to Algorithms).
Traditionally, you start path[i][i] = 0 for each i. But you can instead start from path[i][i] = INFINITY. It won't affect algorithm itself, as those zeroes weren't used in computation anyway (since path path[i][j] will never change for k == i or k == j).
In the end, path[i][i] is the length the shortest cycle going through i. Consequently, you need to find min(path[i][i]) for all i. And if you want cycle itself (not only its length), you can do it just like it's usually done with normal paths: by memorizing k during execution of algorithm.
In addition, you can also use Dijkstra's algorithm to find a shortest cycle going through any given node. If you run this modified Dijkstra for each node, you'll get the same result as with Floyd-Warshall. And since each Dijkstra is O(n^2), you'll get the same O(n^3) overall complexity.
The pseudo code is a simple modification of Dijkstra's algorithm.
for all u in V:
for all v in V:
path[u][v] = infinity
for all s in V:
path[s][s] = 0
H = makequeue (V) .. using pathvalues in path[s] array as keys
while H is not empty:
u = deletemin(H)
for all edges (u,v) in E:
if path[s][v] > path[s][u] + l(u, v) or path[s][s] == 0:
path[s][v] = path[s][u] + l(u,v)
decreaseKey(H, v)
lengthMinCycle = INT_MAX
for all v in V:
if path[v][v] < lengthMinCycle & path[v][v] != 0 :
lengthMinCycle = path[v][v]
if lengthMinCycle == INT_MAX:
print(“The graph is acyclic.”)
else:
print(“Length of minimum cycle is ”, lengthMinCycle)
Time Complexity: O(|V|^3)
Perform DFS
During DFS keep the track of the type of the edge
Type of edges are Tree Edge, Back Edge, Down Edge and Parent Edge
Keep track when you get a Back Edge and have another counter for getting length.
See Algorithms in C++ Part5 - Robert Sedgwick for more details
What you will have to do is to assign another weight to each node which is always 1. Now run any shortest path algorithm from one node to the same node using these weights. But while considering the intermediate paths, you will have to ignore the paths whose actual weights are negative.
Below is a simple modification of Floyd - Warshell algorithm.
V = 4
INF = 999999
def minimumCycleLength(graph):
dist = [[0]*V for i in range(V)]
for i in range(V):
for j in range(V):
dist[i][j] = graph[i][j];
for k in range(V):
for i in range(V):
for j in range(V):
dist[i][j] = min(dist[i][j] ,dist[i][k]+ dist[k][j])
length = INF
for i in range(V):
for j in range(V):
length = min(length,dist[i][j])
return length
graph = [ [INF, 1, 1,INF],
[INF, INF, 1,INF],
[1, INF, INF, 1],
[INF, INF, INF, 1] ]
length = minimumCycleLength(graph)
print length

Resources