【问题标题】:Implementation of Bellman-Ford algorithm in pythonBellman-Ford算法在python中的实现
【发布时间】:2017-01-07 03:12:07
【问题描述】:

我正在为 Coursera 上的“图算法”课程做一个练习,我必须实现 Bellman-Ford 算法来检测图是否有负循环,分别输出 1 和 0。我做了很多压力测试,我的实现工作正常,但是在课程中的一个测试用例中失败了(但除了“错误答案”之外,他们没有提供任何关于它的信息)。我的实现与您在网上找到的相同,因此我看不出我的代码有什么问题。有什么想法吗?

def relax(u,v,w,dist,prev):
    if dist[u]+w < dist[v]:
        dist[v] = dist[u]+w
        prev[v] = u

def bellmanFord(V,E):
    dist = [float('inf')] * V
    prev = [None] * V
    dist[0] = 0

    for i in range(V-1):
        for edge in E:
            relax(edge[0],edge[1],edge[2],dist,prev)

    #checks for negative cycles        
    for e in E:
        u = e[0]
        v = e[1]
        w = e[2]
        if dist[u]+w < dist[v]:
            return 1

    return 0

【问题讨论】:

  • 他们不测试空图,是吗?
  • 或者不是强连接的图?
  • 输入的权重是浮点数还是整数?是否保证图是连通的?
  • 所有图都是有向图,权重为整数,最多 10³,N 条边​​在 1 和 10³ 之间,M 条边在 0 和 10⁴ 之间。这些图没有强连接。当有 1 个或多个顶点且没有边,或者存在循环时(如果顶点与自身连接并且具有负权重,则程序检测到负循环),此代码有效。任何具有正权重的图都被检测为没有负循环。正在发生的事情是,一些具有负权重的图表被视为负循环,或者在应该被视为负循环时,但我找不到错误的测试用例。
  • 交叉发布:stackoverflow.com/q/41517416/781723cs.stackexchange.com/q/68357/755。请do not post the same question on multiple sites。每个社区都应该诚实地回答问题,而不会浪费任何人的时间。

标签: python algorithm graph shortest-path


【解决方案1】:

此代码不适用于未连接的图形 例如,对于以下正确的情况,它给出 1:

edges = []
edges.append([0, 1, 5])
edges.append([2, 3, -5])
edges.append([3, 4, -6])
edges.append([4, 2, -5])
edges.append([1, 2, 5])

print(bellmanFord(5, edges))

演示链接:http://ideone.com/j8XAs3

当我们删除边 1 -> 2 时,它给出了 0,即使图有一个负循环 (2 -> 3 -> 4 -> 2):

edges = []
edges.append([0, 1, 5])
edges.append([2, 3, -5])
edges.append([3, 4, -6])
edges.append([4, 2, -5])

print(bellmanFord(5, edges))

演示链接:http://ideone.com/N4Bljk


编辑:

正如您所说,在您使用每个顶点作为源之后测试用例 #12 通过了,我确实认为该图没有连接,问题是解决方案的时间复杂度增加了它现在是 O(n*n*m) 即大约 10^11 次操作肯定会超时。

所以你可以通过以下方式修改算法:

1) 找到所有连接的组件并分离出该组件的顶点和边,并使用这些顶点和边创建一个新图

2) 假设您现在有 k 个新图,对每个图运行 Bellman Ford。

此外,您以错误的方式使用“强连接”一词,如果从每个顶点到每个其他可能的顶点都有一条路径,则有向图是强连接的。

我看到了您所指的问题,如果我对这个问题是正确的,我认为它是“问题:检测货币汇率异常”,那么问题中给出的示例与它密切相关的事实相矛盾,因为没有办法到达顶点 4,但是图是连通的。

问题中的示例:

4 4
1 2 -5
4 1 2
2 3 2
3 1 1

如果这不是您所指的问题,或者您还有其他疑问,请告诉我。

【讨论】:

  • 感谢 uSemSurprise 的回答。其实我错了,所有的图都必须是强连接的。如果我理解得很好,Bellman-Ford 算法是单源最短路径算法,所以这意味着它只能找到与源相连的负循环。但是你的帖子帮助我得到了关于这个问题的提示。以每个顶点为源应用 BellmanFord 函数,我能够通过练习 (#12),直到 #18,但由于花费了太多时间而失败了。可能我的代码没有检测到正确的距离,并在强连通图中留下了一些顶点。
  • 再次感谢您的回答。这就是问题所在。我做了一个可达性函数,用组号标记每个节点。因此,在示例中,如果我从 1 开始,顶点 1、2、3 将被标记为“0”,而 4 将被标记为“1”。如果开始是 4,每个人都将在“0”组。在这两种情况下它都有效。然后,我在 ech 组的第一个成员中运行 bellmanFord。有了这个,我能够通过案例#12,但再次卡在案例#18。这次只用了 0.13 秒,就得到了“错误答案”。由于花费的时间,我认为它正在检测一个假阴性循环。
  • 如果我以相反的顺序运行 bellmanFord,从最后一组开始,程序再次在代码 #12 处失败,但现在由于超时。如果它发现一个负循环,它会立即返回,这就是在 #18 的情况下必须发生的事情。 #12 和 #18 都必须有大量的顶点和边。无论如何,现在我必须找到一个使其失败的测试用例。这是更新后的代码:http://ideone.com/cczJjq
【解决方案2】:

所以,我找到了练习的解决方案,而且非常简单。问题是使用 float('inf') 来初始化 dist 列表。相反,如果我使用一个巨大的数字,例如 10000000,它可以在我的初始代码上正常工作,而无需扫描所有顶点。它在未连接图的示例中起作用。谢谢你的帮助,我学到了很多!

【讨论】:

  • 使用无穷大总是一个好主意,因为您可能不知道值有多大,请尝试我提供的链接中给出的 python 代码,这是一种更简洁的方法,链接:geeksforgeeks.org/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-04
  • 2020-03-23
  • 1970-01-01
  • 2016-01-27
  • 2015-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多