在负权重的加权DAG中找到两个节点之间的最短路径

时间:2014-04-27 23:50:58

标签: java python algorithm graph dijkstra

我有一个带加权边的连接DAG。权重可以是正数或负数。我有一个名为root的起始节点和一个名为goal的目标节点。我需要找到一条从根到目标的路径,以便在O(V + E)时间内净重尽可能小(如果净重是-ve甚至更好)。

我提出了以下伪代码,它几乎与Dijkstra相同,只是它只进入目标节点而不是所有节点。

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])
    }
}

此算法有效吗?另外,我不太确定这是否必然是O(V + E)。

P.S。:当我遍历图表时,当前节点的权重应始终为&lt; = k?如何找到最短路径,使得整个路径中该路径的权重总是在O(V + E)时间内<= k,只要它存在于图中?

2 个答案:

答案 0 :(得分:1)

有一个非常简单的算法来解决David回答中描述的重现:我们可以使用深度优先搜索和memoization来确保每次我们需要解决结果的所有子问题当前节点已经知道。这隐含地导致我们需要的拓扑顺序:

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]

结果只是dfs(root)

对于想要找到没有前缀超过权重 k 的最短路径的情况,您可以使用目标中的反向DFS:

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]

解决方案是rdfs(goal)

答案 1 :(得分:0)

这里的关键是非循环有向图。如果你放松(即设置d(w)= min(d(w),d(v)+ length(v-> w)))topological order中的弧,那么每个弧,一旦放松,保持放松。通过贝尔曼 - 福特的正确性证明,这意味着距离标签d是正确的。