找到边的权重为1的所有对的距离的最佳算法

时间:2011-05-01 20:23:56

标签: python algorithm dijkstra shortest-path graph-algorithm

正如标题所说,我正在尝试实现一种算法,该算法找出给定图形中所有节点对之间的距离。但还有更多:(可能有助于你的事情)

  • 图表未加权。 意味着可以将所有边缘视为权重为
  • |E| <= 4*|V|
  • 图表非常大(最多144个深度)
  • 图表已定向
  • 可能有周期
  • 我正在用python编写我的代码(如果你引用算法,那么代码也会很好看:))

我知道所有对的 Johnson算法 Floyd-Warshal Dijkstra 。但是当图表具有权重时,这些算法很好。

我想知道我的案例是否有更好的算法,因为这些算法适用于加权图。

谢谢!

10 个答案:

答案 0 :(得分:11)

还有待改进的空间,因为在未加权的图表中,您获得的附加属性不适用于加权图表,即:

  

对于直接连接A到C的任何边缘,您确定通过第三个节点B没有更短的路径。

考虑到这一点,您应该能够简化Dijkstra的算法:您可能知道,它适用于三组节点:

  1. 已知最终最短路径的那些,
  2. 已计算预备距离且
  3. 的那些
  4. 尚未探索的那些。
  5. e(1。)到A(3)的边缘C后,原始Dijkstra会将节点C从(3.)移动到( 2.)。由于上述属性在您的所有图表中都有,因此您可以将其直接添加到集合(1.)中,这样会更有效。

    以下是基本观察:上面概述的过程基本上是BFS(广度优先搜索),即您可以找到某个固定节点vO(|V| + |E|)中任何其他节点的距离。

    您在原始问题中没有提到图表基本上是一个带有一些洞的网格。这是一个更强大的要求,我相信你可以利用它。快速搜索“网格图最短路径”会产生this paper,在最佳情况下承诺O(sqrt(n))。由于你指定的问题结构相当合理,我几乎可以肯定还有几篇你可能想要研究的论文。

答案 1 :(得分:9)

从每个节点运行广度优先搜索。总时间:O(| V | | E |)= O(| V | 2 ),这是最佳的。

答案 2 :(得分:1)

如果所有边缘都未加权但你想看看Edmond的Blossom V算法,我不知道如何测量距离。你想看看http://code.activestate.com/recipes/221251-maximum-cardinality-matching-in-general-graphs。以下是类似的内容:http://wilanw.blogspot.com/2009/09/maximumminimum-weighted-bipartite.html

答案 3 :(得分:1)

Warshall算法如何,具有以下非常简单的实现:

def warshall(graph):
  n = graph.numNodes+1
  W = [ [graph.w(i,j) for j in graph.V()] for i in graph.V() ]
  for k in range(1,n): 
    for i in range(1,n):
      for j in range(1,n):
        W[i][j] = min( W[i][j] , W[i][k]+W[k][j] )
  return W

其中

  • V()生成图表的所有顶点
  • w(i,j)产生边缘(i,j)的权利 - 在你的情况下全部为1或0
  • numNodes生成图表节点的数量。
然而,复杂性是O(n ^ 3)

答案 4 :(得分:1)

我将向您推荐以下论文:Tadao Takaoka撰写的“所有对最短路径问题的子立方成本算法”。对于具有单位权重(实际上最大边权重= O(n ^ 0.624))的图,存在具有亚立方复杂度的顺序算法。

答案 5 :(得分:1)

我假设图表是动态的;否则,没有理由不使用Floyd-Warshall在这么小的图上预先计算所有对的距离;)

假设你有一个点(x,y)的网格,其中0 <= x&lt; = n,0&lt; = y&lt; = n。在移除边缘E:(i,j)&lt; - &gt; (i + 1,j),你将行j分成集合A = {(0,j),...,(i,j)},B = {(i + 1,j),...,( n,j)}使得B中A,b中的点a 强制绕E路由 - 所以你只需重新计算(A,B)中所有对(a,b)的距离。

也许你可以预先计算Floyd-Warshall,并使用类似的东西将每次图形修改的重新计算减少到O(n ^ 2)(左右)......

答案 6 :(得分:1)

我建议您尝试使用networkx,它似乎可以正常运行1000个节点。

以下链接包含未加权图的最短路径算法:

http://networkx.lanl.gov/reference/algorithms.shortest_paths.html

以下是10个节点的示例:

from random import random
import networkx as nx
G=nx.DiGraph()
N=10
#make a random graph
for i in range(N):
    for j in range(i):
        if 4*random()<1:
            G.add_edge(i,j)

print G.adj
print nx.all_pairs_shortest_path(G)
print nx.all_pairs_shortest_path_length(G)

#output:
#Graph ADJ={0: {}, 1: {}, 2: {}, 3: {0: {}, 2: {}}, 4: {}, 5: {0: {}, 3: {}, 4: {}}, 6: {0: {}, 1: {}, 4: {}}, 7: {2: {}, 4: {}, 6: {}}, 8: {1: {}}, 9: {2: {}, 5: {}}}
#PAIRS={0: {0: [0]}, 1: {1: [1]}, 2: {2: [2]}, 3: {0: [3, 0], 2: [3, 2], 3: [3]}, 4: {4: [4]}, 5: {0: [5, 0], 2: [5, 3, 2], 3: [5, 3], 4: [5, 4], 5: [5]}, 6: {0: [6, 0], 1: [6, 1], 4: [6, 4], 6: [6]}, 7: {0: [7, 6, 0], 1: [7, 6, 1], 2: [7, 2], 4: [7, 4], 6: [7, 6], 7: [7]}, 8: {8: [8], 1: [8, 1]}, 9: {0: [9, 5, 0], 2: [9, 2], 3: [9, 5, 3], 4: [9, 5, 4], 5: [9, 5], 9: [9]}}
#LENGTHS={0: {0: 0}, 1: {1: 0}, 2: {2: 0}, 3: {0: 1, 2: 1, 3: 0}, 4: {4: 0}, 5: {0: 1, 2: 2, 3: 1, 4: 1, 5: 0}, 6: {0: 1, 1: 1, 4: 1, 6: 0}, 7: {0: 2, 1: 2, 2: 1, 4: 1, 6: 1, 7: 0}, 8: {8: 0, 1: 1}, 9: {0: 2, 2: 1, 3: 2, 4: 2, 5: 1, 9: 0}}

答案 7 :(得分:0)

在Python Graph项目中:

http://code.google.com/p/python-graph/

您可以找到我对A *算法的实现,并支持提示启发式。这特别适用于二维避障,因为提示算法不需要比pythogras定理更多。

我认为这会做你想要的一切。如果您不喜欢此项目使用的图形抽象,则可以重复使用该算法。它以非常通用的方式编写。

答案 8 :(得分:0)

快速翻阅the Algorithm Design Manual之后,这就是Skiena所说的内容(来自第15.4章 - 最短路径)。不出所料,它得到了许多人已经提供的相同结论,但也提供了一些其他见解

  

找到最短路径的主要算法是Djikstra的算法......

     

您的图表是加权的还是未加权的?如果您的图表未加权,从源顶点开始的简单广度优先搜索将找到线性时间内所有其他顶点的最短路径...

他继续提到你可能感兴趣的其他案例(例如,如果输入是一组几何障碍怎么办?你需要所有点之间的最短路径吗?)但在这些情况下他也得出结论和你一样:Djikstra的算法或Floyd-Warshall算法。

根据您的使用情况,您可能还需要查看处理可达性的Transitive Closures,并使用类似的算法。

答案 9 :(得分:0)

def from_vertex(v, E):
    active = [v]
    step = 0
    result = {v:0}
    while active:
        step += 1
        new_active = []
        for x in active:
            for nh in E[x]:
                if nh not in result:
                    new_active.append(nh)
                    result[nh] = step + 1
        active = new_active
    return result

基本上你从每个顶点做一次洪水填充,你得到任何其他可到达顶点距离那个顶点的最小距离。