没有给定边缘的最短路径

时间:2012-06-05 10:01:39

标签: algorithm shortest-path

假设给出了加权图G(V,E)。

图表包含 N 顶点(从0到N-1 编号)和 M双向边

每个边缘(vi,vj)具有正距离d (即两个顶点vivj之间的距离为d)

在任意两个顶点之间最多有一条边,并且没有自循环(即没有边连接顶点到 本身。)

此外,我们给出 S 源顶点和 D 目标顶点。

Q 为查询数量,每个查询包含一条边 e(x,y)

对于每个查询,我们必须找到从源S到目标D的最短路径,假设原始图中没有边(x,y)。 如果从S到D不存在任何路径,那么我们必须打印编号

约束高0 <=(N,Q,M)<= 25000

如何有效地解决这个问题?

直到现在我所做的是实现简单的 Dijakstra算法。

对于每个查询Q,每次我将(x,y)分配给Infinity 并且找到Dijakstra最短路径

但是这种方法会非常缓慢,因为整体复杂性将是 Q (Dijastra Shortes路径的时间复杂度)*

实施例::

N=6,M=9
S=0 ,D=5

(u,v,cost(u,v))
0 2 4
3 5 8
3 4 1
2 3 1
0 1 1
4 5 1
2 4 5
1 2 1
1 3 3

Total Queries =6

Query edge=(0,1) Answer=7
Query edge=(0,2) Answer=5
Query edge=(1,3) Answer=5
Query edge=(2,3) Answer=6
Query edge=(4,5) Answer=11
Query edge=(3,4) Answer=8

3 个答案:

答案 0 :(得分:3)

首先,计算从源节点到目的地的最短路径树。

其次,遍历所有查询并剪切查询指定边缘的最短路径;这定义了一个最小割问题,你有源节点和一个分区的边界与另一个分区的边界和目的地的距离;您可以非常轻松地计算此问题,最多O(|E|)

因此,此算法需要O(Q|E| + |V|log|V|),比|V|log|V| > |E|时的天真解决方案渐近快。

此解决方案重用了Dijkstra的计算,但仍然单独处理每个查询,因此通过观察由边缘引起的切割形状,在连续查询中利用先前查询中的工作,可能还有改进的空间。

答案 1 :(得分:1)

对于每个查询,图表只会稍微改变,因此您可以重复使用大量计算。

我建议采用以下方法:

  1. 计算从 S 到所有其他节点的最短路径(Dijkstras算法已为您完成此操作)。这将为您提供最短的路径树 T
  2. 对于每个查询,取此树,由查询中的边(x,y)修剪。这可能是原始树(如果(x,y)不在树上的位置)或较小的树 T'
    • 如果 D T'中,您可以采用原始的最短路径
    • 否则启动Dijkstra,但使用 T'中已有的标签(这些路径已经是最小的)作为永久标签。
  3. 如果您在步骤2中运行Dijkstra,您可以通过以下方式重复使用树 T 的部分修剪:每次要将节点标记为永久性(其中一个节点不是在 T'中,您可以将此节点的整个子树(从原始树 T )附加到新的最短路径树,并将其所有节点标记为永久性。

    这样,您可以从第一个最短路径运行中重用尽可能多的信息。


    在你的例子中,这意味着:

    计算最短路径树: 0→1→2→3→4-→5 (在这种情况下非常简单)

    现在假设我们得到查询(1,2)。

    我们修剪边缘(1,2)离开我们 0→1

    从那里我们开始Dijkstra获得2和3作为下一个永久标记节点。 我们在新的最短路径树中连接1到2和1到3并附加3中的旧子树: 2'; -O - &GT; 1→3→4-→5

    所以我们通过运行Dijkstras算法的另一步来获得最短的路径。


    算法的正确性来自树 T 中的所有路径,只要在查询的新图形中(每个最短路径只能更长)。因此,我们可以重用树中仍然可行的每条路径(即没有去除边缘的地方)。

    如果性能很重要,你可以通过很多实现技巧来提高Dijkstra的性能。一个很好的切入点可能是DIMACS Shortest Path Implementation Challenge

答案 2 :(得分:0)

一个简单的优化:首先在完整的图形上运行Dijkstra(没有删除边缘)。

然后,对于每个查询 - 检查请求的边是否属于该最短路径。如果不是 - 删除此边缘将没有任何区别。