一尘不染

Sedgewick和Wayne的Bellman ford基于队列的方法-算法,第4版

algorithm

我正在研究
此链接http://algs4.cs.princeton.edu/44sp/BellmanFordSP.java上针对单个源最短路径的queue- based方法,Bellman-Ford algorithm该方法Robert Sedgewick and Kevin Wayne - Algorithms, 4th edition来自本书的算法。

我有两点,一个是疑问,另一个是代码改进建议。

  1. 在上面的方法中,下面是放松方法的代码,用于放松到顶点的距离。
    for (DirectedEdge e : G.adj(v)) {
    int w = e.to();
    if (distTo[w] > distTo[v] + e.weight()) {
        distTo[w] = distTo[v] + e.weight();
        edgeTo[w] = e;
        if (!onQueue[w]) {
            queue.enqueue(w);
            onQueue[w] = true;
        }
    }
    if (cost++ % G.V() == 0){
        findNegativeCycle();
    }
    

    }

在此方法中,在找到负循环之前使用以下条件。

if (cost++ % G.V() == 0){
     findNegativeCycle();
}

上面他们用成本除以vertices图中的数目来检查negative cycle。可能是因为松弛完成V-1Vth一段时间,并且如果松弛运行了一段时间,则意味着它具有循环,其中V是顶点数。

但是我认为在基于队列的方法中,他们使用除数来定期检查周期是否发生。在上述条件成立之前或之后可能会发生一个周期。如果在上述条件为真之后发生循环,则算法必须等到下一个条件为真时才能检测到循环,如果(cost++ % G.V() == 0)为真,则不必精确地发生循环。因此,我认为除数可以是足够小的任何数字,以便我们可以在适当的时间间隔后检查周期。我是这样认为的吗?

  1. 代码改进建议是,findNegativeCycle()如果发生循环,则可以使用该方法返回true。从而。这个条件-

if (cost++ % G.V() == 0) { findNegativeCycle(); }

可以更改为-

if (cost++ % G.V() == 0)
    if(findNegativeCycle()){
        return;
    }

即使findNegativeCycle()方法找到一个循环,for循环中的代码也会继续运行。因此我们可以返回是否发生循环,而不是处理其余的for循环。

请分享您对以上2点的看法。提前致谢。


阅读 227

收藏
2020-07-28

共1个答案

一尘不染

  1. 你是对的。在其在线资料中,作者解释说,他们检查每个Vth调用以分摊构建相关的边缘加权有向图并在其中找到周期的成本:

因此,为了实现negativeCycle(),BellmanFordSP.java从e​​dgeTo
[]的边缘构建了一个边缘加权的有向图,并在该有向图中寻找一个循环。为了找到循环,它使用EdgeWeightedDirectedCycle.java(第4.3节中DirectedCycle.java的一个版本),适用于边缘加权有向图。
我们仅在每次Vth调用Relax()之后才执行此检查,从而摊销此检查的费用

换句话说,您可以更频繁地检查,但是这样会冒着性能损失的风险。

  1. 同样,你是对的。当前while在构造函数中循环检查是否存在负循环。但是,在最坏的情况下,该relax方法可以通过检查循环中的第一个边沿来检测for循环,而不是退出循环将继续并检查其他边沿(最多V-2)。通过建议的改进可以节省大量时间。
2020-07-28