Bellman-Ford算法:所有最短路径

6

我已经成功地实现了Bellman-Ford算法来查找具有负权重/距离的边的最短路径距离。但是,我无法让它返回所有最短路径(当最短路径存在并列情况时)。我使用Dijkstra算法成功地获得了所有最短路径(在给定节点对之间)。Bellman-Ford算法能否实现这一点?(只是想知道我是否在浪费时间尝试)


从数学上讲,我不确定这是可能的。例如,如果所有边的成本都为零,那么您可以采取无限多个可能的最短路径。您想要最短无环路径吗? - templatetypedef
是的,抱歉,我应该说明一下。我想找到两个节点之间所有最短无环路径。 - user1507844
1个回答

9

如果你稍微修改贝尔曼-福特算法的第二步,你可以实现非常相似的效果:

for i from 1 to size(vertices)-1:
   for each edge uv in edges: // uv is the edge from u to v
       u := uv.source

       if u.distance == INFINITY:
           // skip start nodes that have no valid path from source yet
           continue

       v := uv.destination

       if u.distance + uv.weight < v.distance:
           v.distance := u.distance + uv.weight
           v.predecessor[] := u
       else if u.distance + uv.weight == v.distance:
           if u not in v.predecessor:
               v.predecessor += u

其中 v.predecessor 是一个顶点列表。如果 v 的新距离等于一条尚未包括的路径,请包括新的前驱。

为了打印所有最短路径,你可以使用类似的方法

procedure printPaths(vertex current, vertex start, list used, string path):
    if current == start:
        print start.id + " -> " + path
    else:
        for each edge ve in current.predecessors:
            if ve.start not in used:
                printPaths(ve.start,start, used + ve.start, ve.start.id + " -> " + path)

使用printPaths(stop,start,stop,stop.id)来打印所有路径。

注意:如果在算法完成后删除重复元素,可以将if u not in v.predecessor then v.predecessor += u从修改的算法中排除。


谢谢,这非常有帮助。实际上我已经完成了除递归printPaths过程以外的所有内容,看起来真的很简单。有没有一种方法可以不使用递归打印所有路径呢?更普遍地说,总是可以使用循环代替递归吗? - user1507844
是的,但由于这是一种回溯算法,跟踪“used”变量会很棘手。如果您想创建迭代版本,则必须以某种方式操作“used”列表,而不会创建无限循环。有一些粗略的解决方案,例如构建一个queue [0,...,n-1],其中queue [i]包含第i级的所有可能的前任(queue [0]:=[stop]),并使用n维多索引I来迭代队列。但您必须检查当前集合“I”是否有效。由于您仅使用非循环路径,因此可以使用顶点集的列表来表示“used”。 - Zeta
v.predecessor[] := u 和 v.predecessor += u 有什么区别? - calibr
1
@calibr v.predecessor[] := upredecessor 列表设置为 u 和仅 u,而 v.predecessor += u 则将其添加到列表中。这种表示法在 https://en.wikipedia.org/w/index.php?title=Bellman%E2%80%93Ford_algorithm&oldid=500771237 中有所体现。 - Zeta
我建议再检查一下:u.distance 或者 v.distance 可能都是无穷大(你将距离初始化为无穷大),在这种情况下,如果 u.distance + uv.weight == v.distance 对于图的非连接部分成立,那么你将得到垃圾数据。因此,在该条件中,你应该检查它们中的一个是否不是无穷大。 - Mitar
@Mitar 不错的观点。我已经添加了一个检查条件,判断 u.distance 是否为 INFINITY,这应该足够了。 - Zeta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接