Bellman-Ford负循环的前身不存在

时间:2019-03-29 15:18:34

标签: c# graph bellman-ford

我已经实现了Bellman-Ford算法来检测图中的负周期。值得注意的是,图中的每个边都有一个倒数,因此,如果存在可以从A -> B开始的边,那么也存在可以从B -> A开始的边。

我的问题是当我导航前导链(存储在字典pred中)时。看来源顶点永远都没有前任,所以当我在负循环检查中循环遍历每个顶点时,会引发异常,因为pred永远都没有源顶点的条目

这是什么意思?图中似乎存在一个负周期,但是如果源顶点之前没有任何东西,并且源顶点被“包含”在检测到的负周期中,那么真的有一个周期开始吗?

private List<Vertex> BellmanFord( Vertex source )
{
  var dist = new Dictionary<Vertex, double>();
  var pred = new Dictionary<Vertex, Vertex>();

  // Initialize
  foreach( var vertex in Vertices )
    dist[ vertex ] = double.MaxValue;
  dist[ source ] = 0;

  // Relax
  foreach( var vertex in Vertices )
    foreach( var edge in Edges )
      Relax( edge, ref dist, ref pred );

  // Check for negative cycles
  foreach( var edge in Edges )
  {
    if( dist[ edge.From ] != double.MaxValue )
      if( HasCycle( edge, ref dist )
      {
        var cycle = new List<Vertex>();
        var vertex = edge.From;

        while( vertex == edge.To )
        {
          cycle.Add( vertex );
          vertex = pred[ vertex ];
        }

        cycle.Add( edge.To );
        return cycle;
      }
  }

  return new List<Vertex>(); // No cycle
}

private void Relax( Edge edge, ref Dictionary<Vertex, double> dist, ref Dictionary<Vertex,Vertex> pred )
{
  if( dist[edge.From] == double.MaxValue )
    return;

  var newDist = dist[ edge.From ] + edge.Weight;
  if( newDist < dist[ edge.To] )
  {
    dist[ edge.To ] = newDist;
    pred[ edge.To ] = edge.From;
  }
}

private bool HasCycle( Edge edge, ref Dictionary<Vertex, double> dist )
{
  return dist[edge.To] > dist[edge.From] + edge.Weight;
}

从好的角度出发,每条边的权重均按-1 * Math.Log( value )计算。

1 个答案:

答案 0 :(得分:1)

据我了解,观察到的行为不是表明您的实现中存在错误。 Bellman-Ford算法能够得出一个负长度的循环;这并不意味着可以找到每个长度为负的 个周期。 Floyd-Warshall algorithm可能更适合于此。两种算法都可以解决问题的不同表述。第一个解决单源最短路径问题,第二个解决全对最短路径问题。