Java 负权加权DAG中两节点间最短路径的求解

Java 负权加权DAG中两节点间最短路径的求解,java,python,algorithm,graph,dijkstra,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()

我有一个带加权边的连通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)


注意:如果当我遍历图时,当前节点的权重应该总是,那么这里的关键是非循环有向图。如果您放松(即,设置d(w)=min(d(w),d(v)+长度(v->w)),则每一个圆弧在放松后都保持放松。根据贝尔曼-福特的正确性证明,这意味着距离标签d是正确的。

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

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)

“这个算法有效吗?”-您试过运行它吗?此外,最坏情况下的性能为O(| V | log | V |+| E |),它适用于我为测试目的创建的一些小样本图,但这并不排除它不正确的可能性,是吗?关于Dijkstra,上述算法与Dijkstra略有不同,因此,我认为运行时可能会有所改进。不过我不确定。除了使用上面的算法,我还需要一个O(V+E)算法,我想出了上面的一个——不确定它是否适合正确的解决方案和所需的运行时间。为什么要重新发明轮子?这里有两个经典的算法可以处理负的边权重(Dijkstra没有)。Bellman Ford是O(mn),Floyd Warshall是O(n^3),用于计算所有对中的最短路径。在稠密图中,它们的复杂性是相同的。这些还将为您提供正确的证明方法,以显示您的算法是否有效。谢谢!我知道贝尔曼·福特(还没听说过弗洛伊德·华沙,谢谢)。然而,我需要一个O(V+E)算法,所以贝尔曼·福特不会帮我。另外,与Bellman Ford(或Dijkstra,如果有关系的话)不同,我需要解决单源、单目的地最短路径问题,因此,使用单源、全目的地最短路径算法有点浪费资源。谢谢!这是否意味着上述算法是正确的呢?它的复杂性呢?@SerenaHamilton它是O(| V |+| E |)。谢谢!你能解释一下怎么做吗?以上内容看起来与Dijkstra非常相似,因此我看不出它与Dijkstra的O(V*logV+E)运行时有什么不同。@SerenaHamilton David指的是这个答案中描述的算法,而不是你问题中的算法。您可以通过在时间O(n+m)中执行简单的DFS进行拓扑排序,非常感谢!但我仍然不清楚这是如何给出最短长度的路径的,因为我有一个节点列表、邻接列表、一个开始节点、一个目标节点和一个所有边权重的哈希图。@SerenaHamilton我认为这很清楚。你只需要为所有边(x,y)实现循环
,权重为w:
啊,我现在看到了。谢谢!还有一个问题,一旦我实现了循环,它还会是O(V+E)吗?@SerenaHamilton如果你在O(x的外度)=O(给定x的边数(x,y))中实现它,那么是的。当然,从技术上讲,哈希表不是O(1),但我想你愿意假设它们在实践中(这样做是合理的)等等,为什么O(x的超出度)=O(给定x的边数(x,y))永远不会是真的?