负周期解释的Bellman-ford算法

时间:2018-12-28 05:03:48

标签: python algorithm bellman-ford

我尝试实现BF算法进行负循环检测。

我按照讲座notes来实现算法。 我的解决方案如下:

def belman_ford(s, adj, cost):
    arr_len = len(adj)
    dist_arr = [MAX_VAL]*arr_len
    prev_arr = [None]*arr_len
    dist_arr[s] = 0

    for u in range(arr_len):
        for i, v in enumerate(adj[u]):
            if dist_arr[v] == MAX_VAL:
                break
            if dist_arr[v] > dist_arr[u] + cost[u][i]:
                dist_arr[v] = dist_arr[u] + cost[u][i]
                prev_arr[v] = u


    #detect negative cycle
    for u in range(arr_len):
        for i, v in enumerate(adj[u]):
            if dist_arr[v] == MAX_VAL:
                break
            if dist_arr[v] < dist_arr[u] + cost[u][i]:
                return 1

    return 0


def negative_cycle(adj, cost):
    #write your code here
    return belman_ford(0,adj, cost)

但是,我找到了另一个解决方案来帮助我克服编码挑战。

def negative_cycle(adj, cost):
    distance=[0]*len(adj)
    distance[0] = 0
    for ind in range(len(adj)):
        for u in range(len(adj)):
            for v in adj[u]:
                v_index = adj[u].index(v)
                if distance[v] > distance[u] + cost[u][v_index]:
                    distance[v] = distance[u] + cost[u][v_index]
                    if ind==len(adj) - 1:
                        return 1
    return 0

我无法理解其背后的逻辑。 为什么这个if ind==len(adj) - 1 if语句实际上导致循环检测

作为输入,我得到了邻接和成本清单

1 个答案:

答案 0 :(得分:2)

要了解Bellman-Ford算法的基本概念,请快速浏览Wikipedia

  

Bellman-Ford算法只是放松所有边缘,并进行|V|-1次,其中|V|是图中的顶点数量。

然后您的行if ind==len(adj) - 1的解释是

  

由于最长的无循环路径可能是|V|-1条边,因此必须|V|-1次扫描边,以确保找到所有节点的最短路径。

     

执行所有边缘的最终扫描,并且如果更新了任何距离,则找到了一条长度为|V|个边缘的路径,该路径只有在图形中存在至少一个负循环时才会出现。

Bellman-Ford首先假设距离非常大(无穷大),然后逐渐将距离减小到最低。这称为松弛。在每次迭代中,离源较远一步的边缘都会放松。

S --> A --> B --> C --> D --> E --> F --> G --> H --> I

现在说您有一个没有负循环的图。假设它有10个顶点,则不需要超过9个松弛即可到达(从其获得的)最远顶点。如果经过9次放松后您仍然得到改善,该怎么办?您的图形中必须有负循环。

您代码中的ind是一个计数器。 ind == len(adj) - 1表示您有|V|倍的放松距离,这表明存在负周期。

也请在自己的笔记中查看第三页。