我有这个问题:“带有一个可跳过边缘的最短路径。给定边缘加权有向图,设计E*log(V)
算法以找到从s
到t
的最短路径{{1}}您可以将任何一条边的权重更改为零。假设边权重是非负的。“
我不明白他们要我做什么。将重量变为零意味着什么?我认为我可以将任何最短路径中的任何边缘改为零,它仍然是最短的。
答案 0 :(得分:7)
首先使用Dijkstra找到每个顶点S(v)
从s
到v
的最短路径的v
长度。然后使用Dijkstra找到每个顶点T(v)
从v
到t
的最短路径的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)
现在我们必须逐个选择跳过的边缘。
换句话说,具有一个可跳过边缘的最短路径的长度是
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)
现有的答案是正确的,但是对我来说更直观的另一个想法是变换图形并使用分层的方法:
G
的副本,并将其命名为G'
(u, v)
中的每个边G
,创建从(u, v')
(在u
中)到G
(在{ {1}},重量为v'
。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);
,所以我们永远都不会碰到空的父边缘。
我认为这应该可行,除非我没有想到。