我正在尝试编写一种算法,该算法将在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
这是准确的,但是通过它进行路径重建变得很麻烦。
答案 0 :(得分:1)
这是我对您的功能所做的更改。
next
重命名为next_node
是因为next
实际上是Python关键字。dist
重命名为cost
。next_node
存储为set()
,以避免两次添加相同的元素。set()
时,我确保要创建一个新的k
。那是为了避免意外的数据混叠。您的代码中存在一个错误,即如果从1 - 3 - 2
开始的路由与您将1 - 4 - 2
别名为next[1][2]
的{{1}}相匹配,然后向其中添加next[1][3]
,这可能是错误的4
。 这给了我以下与您非常相似的功能:
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