我尝试实现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语句实际上导致循环检测
作为输入,我得到了邻接和成本清单
答案 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|
倍的放松距离,这表明存在负周期。
也请在自己的笔记中查看第三页。