我需要修改Dijkstra的算法,这样如果有几条最短的路径,我需要找到路径上边数最少的路径。
我一直坚持如何使用Dijkstra的方法找到多条最短路径,你是怎么做到的?它不总是只输出1条最短路径?伪代码或任何一般方向都会非常有用。
答案 0 :(得分:8)
您可以分配到目前为止遍历的边数,而不是为每个节点指定距离源的距离。因此,每个节点只有(distance,edges)
而不是distance
。其他一切照常工作,对于每个终端节点,您记录的值最小为(distance,edges)
。
答案 1 :(得分:3)
维护每个顶点形式dijkstra的maxPathLen字段。
在你比较的循环中
if(distance(s,u)+edge(u,v)<distance(s,v)) {
distance(s,v) = distance(s,u) + edge(u,v)
parent(v) = u
// Add this statement
minPathLen(v) = minPathLen(u) + 1
}
添加另一个声明: -
if((distance(s,u)+egde(u,v)==distance(s,v))&&(minPathLen(u)+1<minPathLen(v))) {
parent(v) = u
minPathLen(v) = minPathLen(u) + 1
}
答案 2 :(得分:3)
另一种选择是在每个边的权重上添加一些小数ε
,其中ε << edgeWeights
(对于整数边权重,您可以选择ε < gcd(edgeWeights)/numberOfEdges
)
这种方法的优点是您不需要编写自己的路径查找器,只需使用任何现成的实现。
答案 3 :(得分:2)
受到BlueRaja
的启发public void updateAdjacencyMatrix()
{
epsilon = 0.001
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
if (adjacencyMatrix[i, j] != 0)
adjacencyMatrix[i, j] = adjacencyMatrix[i, j] + epsilon;
}
}
}
然后在正常的Dijkstra实现中调用 updateAdjacencyMatrix()
答案 4 :(得分:1)
我们可以为每个边添加一个非常小的值(比如说ε)。现在,具有较多边数的路径将具有比具有较少边数的路径更高的成本,而两个路径具有相等的最小路径长度。
但是我们需要注意选择这么小的值,比如说有一条路径先前成本较高,但边缘数量较少,然后在修改此值后,之前较短的路径最终会产生随着加入ε的数量越多,值越高。
为了解决这个问题,我们采用2个最小边之间的差异 。并将该值除以边数以得到ε。
证明 - 假设图表有n个边缘。并且它是包含(n-1)个边缘的最短路径,该边缘稍微高(该值至少是2个最小边缘之间的差值)而不是仅具有1个边缘的另一个路径。因此,在将ε添加到所有边之后,最小路径仍然是最小的至少(n + 1)epsilon,使其比另一条路径长,但它只有(n-1)ε。 修改值后,应用Dijkstra的算法找到s和t之间的最短路径。
复杂性=复杂性调整值+复杂性Dijkstra = O(E + E) lg V)= O(E lg V)
这是python代码 -
from heapq import heappop, heappush
from collections import defaultdict
def createAdjacencyList(Graph,epsilon=0):
AdjacencyList = defaultdict(list)
for Node1, Node2, edgeCost in Graph:
AdjacencyList[Node1].append((edgeCost + epsilon, Node2))
return AdjacencyList
def bestShortestPath(epsilon, s, t, Graph):
processingQ, visited = [(0, s, "")], set()
while processingQ:
# Always return the list item with min cost.
(totalCost,thisVertices,path) = heappop(processingQ)
if thisVertices not in visited:
visited.add(thisVertices)
path = path + thisVertices
if thisVertices == t:
return totalCost - ((len(path) - 1) * epsilon), path
for thisCost, connectedVertices in Graph.get(thisVertices, ()):
if connectedVertices not in visited:
# It's a python inbuilt Heap. Whenever we will do POP , we will get the element with MinCost .
heappush(processingQ, (totalCost+thisCost, connectedVertices, path))
return float("inf")
if __name__ == "__main__":
Graph = [ ("A", "B", 3), ("B", "C", 7), ("C", "D", 8),("D", "E", 2), ("E", "F", 3),
("A", "G", 7), ("B", "G", 6), ("A", "K", 7), ("C", "I",3), ("F", "K", 9),
("G", "H", 4), ("H", "I", 2), ("K", "J", 1), ("G", "L",4), ("I", "M", 3),
("I", "O", 3), ("J", "N", 7), ("L", "M", 6), ("M", "N", 7), ("L", "O", 6),
("M", "O", 1), ("N", "O", 1), ("L", "H", 1), ("M", "E", 3), ("O", "A", 2),
("O", "B", 1), ("O", "C", 1), ("O", "D", 1), ("O", "E", 1), ("K", "N", 8),
]
# value of epsilon is minimumEdgeWeight/totalNumberOfEdges added to each edge
minEdge = min(Graph, key=lambda t: t[2])[2]
secondMinEdge = min(Graph, key=lambda t: [t[2], float("inf")][t[2] == minEdge])[2]
epsilon = (secondMinEdge - minEdge)/ len(Graph)
print(createAdjacencyList(Graph).items())
Graph = createAdjacencyList(Graph, epsilon)
# (16.0, 'AKNO') . Though multiple path exists with value 16.0 like ABCIO,AKJNO
print("Cost and Path from A -> O: is ", bestShortestPath(epsilon, "A", "O", Graph))