最短的路径,一个可跳过的边缘

时间:2013-04-30 03:25:36

标签: graph shortest-path

我有这个问题:“带有一个可跳过边缘的最短路径。给定边缘加权有向图,设计E*log(V)算法以找到从st的最短路径{{1}}您可以将任何一条边的权重更改为零。假设边权重是非负的。“

我不明白他们要我做什么。将重量变为零意味着什么?我认为我可以将任何最短路径中的任何边缘改为零,它仍然是最短的。

5 个答案:

答案 0 :(得分:7)

首先使用Dijkstra找到每个顶点S(v)sv的最短路径的v长度。然后使用Dijkstra找到每个顶点T(v)vt的最短路径的v长度。然后,对于每个边(v, w),使用上面的规则找到总和S(v) + T(w)。最后,选择最小路径。

注意:在这种方法中,我们使边(v,w)权重无效并找到通过(v,w)的最短路径

答案 1 :(得分:4)

问题很简单。

假设你有一条带有一个可跳过边缘的最短路径,p = v1,...,vi,vi + 1,...,vm 和(vi,vi + 1)是跳过的边缘
显然,路径(v1,...,vi)是v1和vi之间的最短路径 路径(vi + 1,...,vm)是vi + 1和vm之间的最短路径 将d(x,y)定义为节点x和节点y之间的最短路径的长度 你可以通过dijkstra算法找到所有节点x的d(s,x)和d(x,t) 现在我们必须逐个选择跳过的边缘。 换句话说,具有一个可跳过边缘的最短路径的长度是

图中所有边(u,v)的

min(d(s,u)+ d(v,t))

由于Dijkstra算法

,时间复杂度为O(E log V)

答案 2 :(得分:2)

之前的答案似乎假设Dijkstra给出了从每个顶点到每个顶点的最短距离,但事实并非如此。

如果你只执行一次Dijkstra,从s开始,你就有从s到每个顶点的最短路径。

为了找到从每个顶点到t的最短距离,有必要在反转图的每个边之后从t开始再次执行Dijkstra。

完整的解决方案是:

1)从s开始在图G上执行Dijkstra,以获得s与任何v之间的最短距离T(v)。

2)反转所有边以获得反转图G'

3)从t开始在图G'上执行Dijkstra,以获得t和任何v之间的最短距离R(v)。

4)要跳过的是边缘e(v1-> v2),其中T(v1)+ R(v2)是最小的。

5)接下来的路径是由第一个Dijkstra给出的s和v1之间的最短路径以及第二个Dijkstra给出的v2和t之间的最短路径的串联。

答案 3 :(得分:1)

现有的答案是正确的,但是对我来说更直观的另一个想法是变换图形并使用分层的方法:

  1. 创建图G的副本,并将其命名为G'
  2. 对于(u, v)中的每个边G,创建从(u, v')(在u中)到G(在{ {1}},重量为v'
  3. 使用任何标准的最短路径算法(例如Dijkstra)来计算从G'0的最短路径。

答案 4 :(得分:1)

当我在Coursera上做普林斯顿算法课程时遇到了这个问题。我得到了公认的答案,但是我想出了一种方法,我认为应该提供一条最短的路径,即从s到任何其他边缘的一条跳过边缘。

我们将使用以下类来存储加权的定向边信息:

public class DirectedEdge implements Comparable<DirectedEdge> {

    private int from;
    private int to;
    private double weight;

    ... boilerplate stuff...

但是,我们还将添加一个装饰器类:

public static class SkipPathEdge {
        DirectedEdge directedEdge;
        double longest;

        public SkipPathEdge(DirectedEdge directedEdge, double longest) {
            this.directedEdge = directedEdge;
            this.longest = longest;
        }
    }

最长,表示到顶点的最短已知路径中的最长已知段。

其余是相当标准的Djikstra,带有索引的最低优先级队列和所有队列,但是稍微修改了松弛方法:

private void relax(EdgeWeightedDigraph G, int e) {
        SkipPathEdge parentEdge = edgeTo[e];

        for (DirectedEdge edge : G.adj(e)) {
            double longest = Math.max(parentEdge.longest, edge.getWeight());
            double adjustment = longest - parentEdge.longest;
            SkipPathEdge childEdge = new SkipPathEdge(edge, longest);

            int from = edge.getFrom(), to = edge.getTo();
            if (distTo[to] > distTo[from] + edge.getWeight() - adjustment) {
                distTo[to] = distTo[from] + edge.getWeight() - adjustment;
                edgeTo[to] = childEdge;
                if (minPQ.contains(to)) {
                    minPQ.changeKey(to, distTo[to]);
                } else {
                    minPQ.addKey(to, distTo[to]);
                }
            }
        }
    }

为了明确起见,我们将edgeTo [s]初始化为new SkipPathEdge(null, 0);,所以我们永远都不会碰到空的父边缘。

我认为这应该可行,除非我没有想到。