Sof*_*mur 5 algorithm graph-theory dijkstra bellman-ford floyd-warshall
我使用矩阵d来呈现图形。d.(i).(j)装置之间的距离i和j; v表示图中的节点数。
此图中可能存在负循环。
我想检查是否存在负循环。我从Floyd-Warshall的变体中写了以下内容:
let dr = Matrix.copy d in
(* part 1 *)
for i = 0 to v - 1 do
dr.(i).(i) <- 0
done;
(* part 2 *)
try
for k = 0 to v - 1 do
for i = 0 to v - 1 do
for j = 0 to v - 1 do
let improvement = dr.(i).(k) + dr.(k).(j) in
if improvement < dr.(i).(j) then (
if (i <> j) then
dr.(i).(j) <- improvement
else if improvement < 0 then
raise BreakLoop )
done
done
done;
false
with
BreakLoop -> true
Run Code Online (Sandbox Code Playgroud)
我的问题是
part 1有用的?因为我经常调用这个函数,我真的很想尽可能快地完成它。所以我的 3) 问题是其他算法(尤其是Bellman-Ford)是否可以比这更快?
关于代码正确性的第一个问题更适合http://codereview.stackexchange.com。
贝尔曼-福特法或弗洛伊德-沃歇尔法都适合解决这个问题。性能对比如下:
O(|V|*|E|)O(|V|)O(|V|^3)O(|V|^2)由于|E|的边界是|V|^2,贝尔曼-福特显然是赢家,我建议您使用它。
如果没有负循环的图形是预期的正常情况,那么作为算法的第一步进行快速检查可能是合适的:图形是否包含任何负边?如果不是,那么它当然不包含任何负循环,并且您有一个O(|E|)最佳情况算法来检测任何负循环的存在。
尽管Timothy Shield 的答案中列出的选项都是在有向加权图中找到负循环的正确算法,但它们并不是最快的。
在这种情况下,我的首选算法始终是Shortest Path Faster Algorithm。
尽管它的最坏情况时间复杂度为O(|V|*|E|),与 Bellman-Ford 相同,但实际上很少有图的 SPFA 达到该时间。在实践中,它要快得多,甚至达到(未经证实的)平均时间O(|E|)。
我在我的博客中写了一篇文章,解释了使用 SPFA 查找负循环的详细信息。
如果您不想阅读全文,您需要的伪代码如下。
function SPFA(G):
for v in V(G):
len[v] = 0
dis[v] = 0
Queue.push(v)
while !Queue.is_empty():
u = Queue.pop()
for (u, v) in E(G):
if dis[u] + w(u, v) < dis[v]:
len[v] = len[u] + 1
if len[v] == n:
return "negative cycle detected"
dis[v] = dis[i] + w(u, v)
if !Queue.contains(v):
Queue.push(v)
return "no negative cycle detected"
Run Code Online (Sandbox Code Playgroud)