Question

I have a connected DAG with weighted edges. The weights can be positive or negative. And I have a start node called root and a goal node called goal. I need to find a path from root to goal such that the net weight is as small as possible (if net weight is -ve it's even better) in O(V + E) time.

I came up with the following pseudocode which is almost identical to Dijkstra's except it goes to only the goal node instead of all nodes.

Q = PriorityQueue()
Q.insert(root, 0)
while (Q is not empty) {
    node = Q.extractMin()
    if (node == goal) {
        return path from node to goal
    }
    else {
        for (x in adjacent[node]) {
            Q.insert(x, weight[x])
    }
}

Does this algorithm work? Also, I'm not very sure if this is necessarily O(V + E).

P.S.: What if the weight upto the current node as I traverse the graph should always be <= k? How can I find the shortest path such that weight of that path throughout the entire path is always <= k in O(V + E) time provided it exists in the graph?

Was it helpful?

Solution

There's a very simple algorithm to solve the recurrence described in David's answer: We can use depth-first search with memoization to ensure that at every time all the subproblems that we need to solve the result for the current node are already known. This implicitly results in the topological order we need:

for all nodes x: 
    dis[x] = UNKNOWN
def dfs(x):
    if x == goal: return 0
    if dis[x] != UNKNOWN: return x
    dis[x] = infinity
    for all edges (x,y) with weight w:
        dis[x] = min(dis[x], w + dfs(y))
    return dis[x]

The result is just dfs(root)

For the case where you want to find a shortest path with no prefix ever exceeding weight k, you can use a reverse DFS from the goal:

for all nodes x: 
    dis[x] = UNKNOWN
def rdfs(x):
    if x == root: return 0
    if dis[x] != UNKNOWN: return x
    dis[x] = infinity
    for all edges (y,x) with weight w:
        dis[x] = min(dis[x], w + rdfs(y))
    if dis[x] > k:
        dis[x] = infinity
    return dis[x]

The solution is rdfs(goal).

OTHER TIPS

The key here is acyclic directed graph. If you relax (i.e., set d(w) = min(d(w), d(v) + length(v->w))) the arcs in topological order, then every arc, once relaxed, stays relaxed. By the correctness proof of Bellman--Ford, this means that the distance labels d are correct.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top