找到边数最少的最短路径

时间:2013-11-18 07:01:33

标签: algorithm dijkstra shortest-path

我需要修改Dijkstra的算法,这样如果有几条最短的路径,我需要找到路径上边数最少的路径。

我一直坚持如何使用Dijkstra的方法找到多条最短路径,你是怎么做到的?它不总是只输出1条最短路径?伪代码或任何一般方向都会非常有用。

5 个答案:

答案 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))