【问题标题】:k shortest paths implementation in Igraph/networkx (Yen's algorithm)Igraph/networkx 中的 k 最短路径实现(Yen 算法)
【发布时间】:2013-03-30 11:34:08
【问题描述】:

经过深入研究并基于thisthis 等,我被建议实施 k 最短路径算法,以便在大型无向中找到第一、第二、第三……第 k 条最短路径,循环,加权图。大约2000个节点。

Wikipedia 上的伪代码是这样的:

function YenKSP(Graph, source, sink, K):
  //Determine the shortest path from the source to the sink.
 A[0] = Dijkstra(Graph, source, sink);
 // Initialize the heap to store the potential kth shortest path.
 B = [];

for k from 1 to K:
   // The spur node ranges from the first node to the next to last node in the shortest path.
   for i from 0 to size(A[i]) − 1:

       // Spur node is retrieved from the previous k-shortest path, k − 1.
       spurNode = A[k-1].node(i);
       // The sequence of nodes from the source to the spur node of the previous k-shortest path.
       rootPath = A[k-1].nodes(0, i);

       for each path p in A:
           if rootPath == p.nodes(0, i):
               // Remove the links that are part of the previous shortest paths which share the same root path.
               remove p.edge(i, i) from Graph;

       // Calculate the spur path from the spur node to the sink.
       spurPath = Dijkstra(Graph, spurNode, sink);

       // Entire path is made up of the root path and spur path.
       totalPath = rootPath + spurPath;
       // Add the potential k-shortest path to the heap.
       B.append(totalPath);

       // Add back the edges that were removed from the graph.
       restore edges to Graph;

   // Sort the potential k-shortest paths by cost.
   B.sort();
   // Add the lowest cost path becomes the k-shortest path.
   A[k] = B[0];
return A;

主要问题是我还不能为此编写正确的 python 脚本(删除边缘并将它们正确放回原处),所以我只能像往常一样依靠 Igraph 做到这一点:

def yenksp(graph,source,sink, k):
    global distance
    """Determine the shortest path from the source to the sink."""
    a = graph.get_shortest_paths(source, sink, weights=distance, mode=ALL, output="vpath")[0]
    b = [] #Initialize the heap to store the potential kth shortest path
    #for xk in range(1,k):
    for xk in range(1,k+1):
        #for i in range(0,len(a)-1):
        for i in range(0,len(a)):
            if i != len(a[:-1])-1:
                spurnode = a[i]
                rootpath = a[0:i]
                #I should remove edges part of the previous shortest paths, but...:
                for p in a:
                    if rootpath == p:
                        graph.delete_edges(i) 

            spurpath = graph.get_shortest_paths(spurnode, sink, weights=distance, mode=ALL, output="vpath")[0]
            totalpath = rootpath + spurpath
            b.append(totalpath)
            # should restore the edges
            # graph.add_edges([(0,i)]) <- this is definitely not correct.
            graph.add_edges(i)
        b.sort()
        a[k] = b[0]
    return a

这是一个非常糟糕的尝试,它只返回列表中的一个列表

我不太确定自己在做什么,而且我已经对这个问题感到非常绝望,在过去的几天里,我对此的看法发生了 180 度甚至一次的转变。 我只是一个尽力而为的菜鸟。请帮忙。也可以建议 Networkx 实现。

附:很可能没有其他工作方法可以解决这个问题,因为我们已经在这里进行了研究。我已经收到了很多建议,我欠社区很多。 DFS 或 BFS 不起作用。图很大。

编辑:我一直在更正 python 脚本。简而言之,这个问题的目的是正确的脚本。

【问题讨论】:

    标签: python graph path networkx igraph


    【解决方案1】:

    我遇到了和你一样的问题,所以我将 Yen 算法的 Wikipedia 伪代码移植到 Python 中与 igraph 库一起使用。

    你可以在那里找到它:https://gist.github.com/ALenfant/5491853

    【讨论】:

      【解决方案2】:

      在 Github 上有一个 Yen 的 KSP 的 python 实现,YenKSP。充分感谢作者,这里给出了算法的核心:

      def ksp_yen(graph, node_start, node_end, max_k=2):
          distances, previous = dijkstra(graph, node_start)
      
          A = [{'cost': distances[node_end], 
                'path': path(previous, node_start, node_end)}]
          B = []
      
          if not A[0]['path']: return A
      
          for k in range(1, max_k):
              for i in range(0, len(A[-1]['path']) - 1):
                  node_spur = A[-1]['path'][i]
                  path_root = A[-1]['path'][:i+1]
      
                  edges_removed = []
                  for path_k in A:
                      curr_path = path_k['path']
                      if len(curr_path) > i and path_root == curr_path[:i+1]:
                          cost = graph.remove_edge(curr_path[i], curr_path[i+1])
                          if cost == -1:
                              continue
                          edges_removed.append([curr_path[i], curr_path[i+1], cost])
      
                  path_spur = dijkstra(graph, node_spur, node_end)
      
                  if path_spur['path']:
                      path_total = path_root[:-1] + path_spur['path']
                      dist_total = distances[node_spur] + path_spur['cost']
                      potential_k = {'cost': dist_total, 'path': path_total}
      
                      if not (potential_k in B):
                          B.append(potential_k)
      
                  for edge in edges_removed:
                      graph.add_edge(edge[0], edge[1], edge[2])
      
              if len(B):
                  B = sorted(B, key=itemgetter('cost'))
                  A.append(B[0])
                  B.pop(0)
              else:
                  break
      
          return A
      

      【讨论】:

      • 这确实使我离解决方案更近了一步,因为我可以分析他如何存储-删除边缘,然后将它们添加回来。无论如何,很难遵循这个示例,因为它调用了他为 DiGraph 编写的脚本,其中涉及许多库,希望在这种情况下没有必要(包括我认为调用外部函数的库)。我将继续向 Igraph 介绍这一点,我们将拭目以待。谢谢你。这可能是答案,但我还没有看到。我分析一下。
      • 在花费时间使用维基百科上的算法和上面这个例子的基础上之后,我设法构建了它。只需要在使用 Igraph(可能还有其他库)时注意,在该方法中最好使用图的深层副本。这样,当您重新添加边时,它不会弄乱原始图形的边 ID-s,因此您可以继续使用它。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 2014-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多