假设给出了加权图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
答案 0 :(得分:3)
首先,计算从源节点到目的地的最短路径树。
其次,遍历所有查询并剪切查询指定边缘的最短路径;这定义了一个最小割问题,你有源节点和一个分区的边界与另一个分区的边界和目的地的距离;您可以非常轻松地计算此问题,最多O(|E|)
。
因此,此算法需要O(Q|E| + |V|log|V|)
,比|V|log|V| > |E|
时的天真解决方案渐近快。
此解决方案重用了Dijkstra的计算,但仍然单独处理每个查询,因此通过观察由边缘引起的切割形状,在连续查询中利用先前查询中的工作,可能还有改进的空间。
答案 1 :(得分:1)
对于每个查询,图表只会稍微改变,因此您可以重复使用大量计算。
我建议采用以下方法:
如果您在步骤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(没有删除边缘)。
然后,对于每个查询 - 检查请求的边是否属于该最短路径。如果不是 - 删除此边缘将没有任何区别。