当前位置: 首页 > 知识库问答 >
问题:

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

钱星华
2023-03-14

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

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

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)

到目前为止,一切似乎都很顺利。

对于路径重建,

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

但这不管用。那么,有没有人可以修改getpath函数(或者编写一个更有效的函数),这样我就可以得到每对顶点之间的所有最短路径(与最短路径绑定的路径)?

对于上面的图表,我有

next=
[[[-1], [3, 2], [2], [3, 2]],
 [[0], [-1], [2], [2]],
 [[3], [3], [-1], [3]],
 [[0, 1], [1], [1], [-1]]]

这是准确的,但通过它重建路径变得相当麻烦。

共有1个答案

韦知
2023-03-14

以下是我对你的功能所做的更改。

  1. 我将next重命名为next_节点,因为next实际上是一个Python关键字
  2. 我将dist重命名为cost,以便更具描述性
  3. 我将next_node存储为set(),以避免将同一个元素添加两次
  4. 当路径通过k时,我确保创建一个新的set()。这是为了避免无意中的数据混淆。您的代码有一个错误,如果从1-3-2next[1][2]的路径与您别名为next[1][2]next[1][3]的路径匹配,则将4添加到该路径中,这对于next[1][3]可能是错误的
  5. 我考虑到了这样一个事实,即您的格式允许节点之间有多条边

这给了我以下功能,这是非常相似的你:

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

然后我以迭代器的形式编写了所有路径。这让事情变得非常简单。两点之间也可能有很多很多路径,在这种情况下,迭代器可以避免使用太多内存。如果你愿意,你可以很容易地把它从迭代器变成数组。以下是该函数:

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

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

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_node = floyd_warshall(n,edge)
for i in range(4):
    for j in range(4):
        for path in all_paths(next_node, i, j):
            print((i, j, path))
 类似资料:
  • 我有一个加权无向图。给定该图中的两个顶点之间没有路径,我想通过向图中添加边来创建它们之间的路径,尽可能少地增加图的总权重。是否有已知的算法来确定要添加哪些边? 一个类似的问题是,如果我有一个国家道路系统的图表,其中有两个城市彼此无法通过道路进入,我想修建一组最短的新道路来连接它们。它们之间可能有其他城市与两者都没有联系,如果它们存在,我想利用它们。 这里有一个小例子;红色和绿色是我要连接的顶点,黑

  • 下面的堆栈溢出问题 我尝试了在语句中使用两个重复的多个构造,但无法为每个起始顶点获得独立的。我也在使用平台,因此它限制了Gremlin的使用,其中不允许使用循环/脚本。所有gremlin查询必须以并由与链接在一起的命令组成 https://docs.aws.amazon.com/neptune/latest/userguide/access-graph-gremlin-differences.ht

  • 因此,如果我在一个图中有两个顶点,它们通过一个以上的边连接,而它们之间有相同的最短路径(即,如果我有节点a和节点B,它们直接通过三条边连接(它们之间有三条最短路径,每个距离为1),所以计数应该返回3)我该如何修改BFS算法来实现这一点?这是我的代码,它只计算2个节点之间的最短路径,而不计算这些最短路径的个数。

  • 以下是练习: null null 我的算法正确吗?如果我做v到w,然后做w到v,这仍然被认为是线性时间吗?

  • 我们有一个边带正权的有向图G(V,E),作为源顶点s,目标点T。此外,最短的s-t路径包括图中的每一个其他顶点。我需要计算s和t之间的交替最短路径距离,以防某些边e∈e被删除。我想设计一个O(e^2logV)算法,它计算图G\e中所有e∈e的最短S-T路径距离。最后的输出应该是一个大小为E的数组,其中edge E的条目应该包含G\E中最短的S-T路径距离。

  • 我试图通过在MST中添加新顶点来更新MST。为此,我一直在关注Chin和Houck的“更新生成树”。http://www.computingscience.nl/docs/vakken/al/WerkC/UpdatingSpanningTrees.pdf 论文中的一个步骤要求我在两个给定顶点之间的路径中找到最大的边。我的想法是找到顶点之间所有可能的路径,然后从这些路径中找到最大的边。我一直在尝试在