重建2个顶点之间的多个最短路径的路径

时间:2019-07-23 13:22:55

标签: python-3.x algorithm floyd-warshall

我正在尝试编写一种算法,该算法将在Floyd-Warshall算法的所有顶点对之间重建最短路径(多条路径,如果有的话,则为最短路径)。我从这里的问题中得到了一些提示:https://stackoverflow.com/a/11371588/7447425

基于此,我修改了Floyd-Warshall算法:

Firebase

该图形采用边列表的形式,例如:

from math import inf

def floyd_warshall(n, edge):
    rn = range(n)
    dist = [[inf] * n for i in rn]
    next  = [[-1]   * n for i in rn]

    for i in rn:
        for j in rn:
            next[i][j]=[-1]

    for i in rn:
        dist[i][i] = 0

    for u, v, w in edge:
        dist[u][v] = w
        next[u][v]=[v]

    for k in rn:
        for i in rn:
            for j in rn:   
                sum_ik_kj = dist[i][k] + dist[k][j]
                if dist[i][j] > sum_ik_kj:
                   dist[i][j] = sum_ik_kj
                   next[i][j]=nxt[i][k]

                elif(sum_ik_kj==dist[i][j] and dist[i][j]!=inf and k!=j and k!=i):
                   next[i][j].extend(next[i][k])

return next

到目前为止,一切似乎都运转良好。

对于路径重建,

edge = [[0,2,2],[2,3,2],[3,1,1],[1,0,4],[1,2,3],[0,3,4],[3,0,5]]
# Here n is the value of the highest numbered-vertex. In the above graph, n=4
n=4
next=floyd_warshall(n,edge)

但这不起作用。那么,谁能善意地纠正getpath函数(或编写一个更有效的函数),以便我可以获取每对顶点之间的所有最短路径(为最短路径绑定的路径)?

对于上面的图形,我有

for i in range(n):
    for j in range(n):
        if(i!=j):
            allPaths=[]
            allPaths=getpath(i,j,next,allPaths)
            print(allPaths)

def getpath(i,j,nxt,allPaths):
    for k in next[i][j]:
        if(k==-1):
            allPaths.extend([i,j])

        elif(k==j):
            allPaths.append(j)

        else:
            paths_I_K=getpath(i,k,next,allPaths)
            paths_K_J=getpath(k,j,next,allPaths)
            for i_k in paths_I_K:
                for k_j in paths_K_J:
                    i_k.pop()
                    allPaths.append(i_k+k_j)
    return allPaths

这是准确的,但是通过它进行路径重建变得很麻烦。

1 个答案:

答案 0 :(得分:1)

这是我对您的功能所做的更改。

  1. 我将next重命名为next_node是因为next实际上是Python关键字。
  2. 为了更具有描述性,我将dist重命名为cost
  3. 我将next_node存储为set(),以避免两次添加相同的元素。
  4. 当路径通过set()时,我确保要创建一个新的k。那是为了避免意外的数据混叠。您的代码中存在一个错误,即如果从1 - 3 - 2开始的路由与您将1 - 4 - 2别名为next[1][2]的{​​{1}}相匹配,然后向其中添加next[1][3],这可能是错误的4
  5. 我考虑到您的格式允许节点之间有多个边缘的事实。

这给了我以下与您非常相似的功能:

next[1][3]

然后我写了def floyd_warshall(n, edge): rn = range(n) cost = [[inf] * n for i in rn] next_node = [[set() for j in rn] for i in rn] for i in rn: cost[i][i] = 0 for u, v, w in edge: # The data format allows multiple edges between two nodes. if w < cost[u][v]: cost[u][v] = w next_node[u][v] = set([v]) elif w == cost[u][v] and w < inf: next_node[u][v].add(v) for k in rn: for i in rn: for j in rn: cost_ik_kj = cost[i][k] + cost[k][j] if cost_ik_kj < cost[i][j]: cost[i][j] = cost_ik_kj next_node[i][j] = set(next_node[i][k]) # Want a copy. elif cost_ik_kj == cost[i][j] and cost_ik_kj < inf: next_node[i][j].update( next_node[i][k] ) return next_node 作为迭代器。这使其非常简单。两点之间也可能有很多很多路径,并且在这种情况下,迭代器可以避免使用过多的内存。而且,如果需要,您总是可以非常轻松地将其从迭代器转换为数组。这是该功能:

all_paths

下面是一些测试代码来演示它:

def all_paths(next_node, i, j):
    if 0 == len(next_node[i][j]):
        if i == j:
            yield [j]
        else:
            pass # There is no path.
    else:
        for k in next_node[i][j]:
            for rest in all_paths(next_node, k, j):
                yield [i] + rest
相关问题