📜  使用最短路径更快算法检测图中的负循环

📅  最后修改于: 2021-10-25 03:14:40             🧑  作者: Mango

给定一个由值为[0, N – 1]的节点、一个源S和一个类型为 { u, v, w } 的数组Edges[][3]组成的图G 它表示节点uv权重为w ,任务是检查给定源是否存在负循环。如果发现是真的,则打印“是” 。否则,打印“否”

例子:

方法:这个想法是使用最短路径更快算法(SPFA)来查找负循环是否存在并且是否可以从图中的源顶点到达。请按照以下步骤解决问题:

  • 用大值初始化数组dis[] ,用 false 和cnt[]初始化数组vis[ ]以存储有关顶点松弛次数的计数。
  • 使用 SPFA 算法遍历图。
  • 每当顶点放松时,增加每个顶点的计数。
  • 停止算法并在某个顶点第N放松后立即打印“是” ,因为只有N个顶点,即从0N – 1
  • 否则,打印“否”

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
bool sfpa(int V, int src, int Edges[][3],
          int M)
{
    // Stores the adjacency list of
    // the given graph
    vector > g[V];
 
    // Create Adjacency List
    for (int i = 0; i < M; i++) {
 
        int u = Edges[i][0];
        int v = Edges[i][1];
        int w = Edges[i][2];
 
        g[u].push_back({ v, w });
    }
 
    // Stores the distance of all
    // reachable vertex from source
    vector dist(V, INT_MAX);
 
    // Check if vertex is present
    // in queue or not
    vector inQueue(V, false);
 
    // Counts the relaxation for
    // each vertex
    vector cnt(V, 0);
 
    // Distance from src to src is 0
    dist[src] = 0;
 
    // Create a queue
    queue q;
 
    // Push source in the queue
    q.push(src);
 
    // Mark source as visited
    inQueue[src] = true;
 
    while (!q.empty()) {
 
        // Front vertex of Queue
        int u = q.front();
        q.pop();
 
        inQueue[u] = false;
 
        // Relaxing all edges of
        // vertex from the Queue
        for (pair x : g[u]) {
 
            int v = x.first;
            int cost = x.second;
 
            // Update the dist[v] to
            // minimum distance
            if (dist[v] > dist[u] + cost) {
 
                dist[v] = dist[u] + cost;
 
                // If vertex v is in Queue
                if (!inQueue[v]) {
                    q.push(v);
                    inQueue[v] = true;
                    cnt[v]++;
 
                    // Negative cycle
                    if (cnt[v] >= V)
                        return true;
                }
            }
        }
    }
 
    // No cycle found
    return false;
}
 
// Driver Code
int main()
{
    // Number of vertices
    int N = 4;
 
    // Given source node src
    int src = 0;
 
    // Number of Edges
    int M = 4;
 
    // Given Edges with weight
    int Edges[][3] = { { 0, 1, 1 },
                       { 1, 2, -1 },
                       { 2, 3, -1 },
                       { 3, 0, -1 } };
 
    // If cycle is present
    if (sfpa(N, src, Edges, M) == true)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
 
    return 0;
}


Java
// Java program for
// the above approach
import java.util.*;
class GFG{
     
static class pair
{
  int first, second;
  public pair(int first,
              int second) 
  {
    this.first = first;
    this.second = second;
  }   
}
   
static boolean sfpa(int V, int src,
                    int Edges[][], int M)
{
  // Stores the adjacency list of
  // the given graph
  Vector []g = new Vector[V];
  for (int i = 0; i < V; i++)
  {
    g[i] = new Vector();
  }
 
  // Create Adjacency List
  for (int i = 0; i < M; i++)
  {
    int u = Edges[i][0];
    int v = Edges[i][1];
    int w = Edges[i][2];
    g[u].add(new pair(v, w));
  }
 
  // Stores the distance of all
  // reachable vertex from source
  int []dist = new int[V];
  Arrays.fill(dist, Integer.MAX_VALUE);
 
  // Check if vertex is present
  // in queue or not
  boolean []inQueue = new boolean[V];
 
  // Counts the relaxation for
  // each vertex
  int []cnt = new int[V];
 
  // Distance from src
  // to src is 0
  dist[src] = 0;
 
  // Create a queue
  Queue q = new LinkedList<>();
 
  // Push source in the queue
  q.add(src);
 
  // Mark source as visited
  inQueue[src] = true;
 
  while (!q.isEmpty())
  {
    // Front vertex of Queue
    int u = q.peek();
    q.remove();
 
    inQueue[u] = false;
 
    // Relaxing all edges of
    // vertex from the Queue
    for (pair x : g[u])
    {
      int v = x.first;
      int cost = x.second;
 
      // Update the dist[v] to
      // minimum distance
      if (dist[v] > dist[u] + cost)
      {
        dist[v] = dist[u] + cost;
 
        // If vertex v is in Queue
        if (!inQueue[v])
        {
          q.add(v);
          inQueue[v] = true;
          cnt[v]++;
 
          // Negative cycle
          if (cnt[v] >= V)
            return true;
        }
      }
    }
  }
 
  // No cycle found
  return false;
}
 
// Driver Code
public static void main(String[] args)
{
  // Number of vertices
  int N = 4;
 
  // Given source node src
  int src = 0;
 
  // Number of Edges
  int M = 4;
 
  // Given Edges with weight
  int Edges[][] = {{0, 1, 1},
                   {1, 2, -1},
                   {2, 3, -1},
                   {3, 0, -1}};
 
  // If cycle is present
  if (sfpa(N, src, Edges, M) == true)
    System.out.print("Yes" + "\n");
  else
    System.out.print("No" + "\n");
}
}
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program for the above approach
import sys
 
def sfpa(V, src, Edges, M):
     
    # Stores the adjacency list of
    # the given graph
    g = [[] for i in range(V)]
 
    # Create Adjacency List
    for i in range(M):
        u = Edges[i][0]
        v = Edges[i][1]
        w = Edges[i][2]
 
        g[u].append([v, w])
 
    # Stores the distance of all
    # reachable vertex from source
    dist = [sys.maxsize for i in range(V)]
 
    # Check if vertex is present
    # in queue or not
    inQueue = [False for i in range(V)]
 
    # Counts the relaxation for
    # each vertex
    cnt = [0 for i in range(V)]
 
    # Distance from src to src is 0
    dist[src] = 0
 
    # Create a queue
    q = []
 
    # Push source in the queue
    q.append(src)
 
    # Mark source as visited
    inQueue[src] = True
 
    while (len(q)):
         
        # Front vertex of Queue
        u = q[0]
        q.remove(q[0])
 
        inQueue[u] = False
 
        # Relaxing all edges of
        # vertex from the Queue
        for x in g[u]:
            v = x[0]
            cost = x[1]
 
            # Update the dist[v] to
            # minimum distance
            if (dist[v] > dist[u] + cost):
                dist[v] = dist[u] + cost
 
                # If vertex v is in Queue
                if (inQueue[v] == False):
                    q.append(v)
                    inQueue[v] = True
                    cnt[v] += 1
 
                    # Negative cycle
                    if (cnt[v] >= V):
                        return True
 
    # No cycle found
    return False
 
# Driver Code
if __name__ == '__main__':
     
    # Number of vertices
    N = 4
 
    # Given source node src
    src = 0
 
    # Number of Edges
    M = 4
 
    # Given Edges with weight
    Edges = [ [ 0, 1, 1 ],
              [ 1, 2, -1 ],
              [ 2, 3, -1 ],
              [ 3, 0, -1 ] ]
 
    # If cycle is present
    if (sfpa(N, src, Edges, M) == True):
        print("Yes")
    else:
        print("No")
 
# This code is contributed by SURENDRA_GANGWAR


C#
// C# program for
// the above approach
using System;
using System.Collections.Generic;
class GFG{
     
class pair
{
  public int first, second;
  public pair(int first,
              int second) 
  {
    this.first = first;
    this.second = second;
  }   
}
   
static bool sfpa(int V, int src,
                 int [,]Edges, int M)
{
  // Stores the adjacency list of
  // the given graph
  List []g = new List[V];
  for (int i = 0; i < V; i++)
  {
    g[i] = new List();
  }
 
  // Create Adjacency List
  for (int i = 0; i < M; i++)
  {
    int u = Edges[i, 0];
    int v = Edges[i, 1];
    int w = Edges[i, 2];
    g[u].Add(new pair(v, w));
  }
 
  // Stores the distance of all
  // reachable vertex from source
  int []dist = new int[V];
  for (int i = 0; i < V; i++)
    dist[i] = int.MaxValue;
 
  // Check if vertex is present
  // in queue or not
  bool []inQueue = new bool[V];
 
  // Counts the relaxation for
  // each vertex
  int []cnt = new int[V];
 
  // Distance from src
  // to src is 0
  dist[src] = 0;
 
  // Create a queue
  Queue q = new Queue();
 
  // Push source in the queue
  q.Enqueue(src);
 
  // Mark source as visited
  inQueue[src] = true;
 
  while (q.Count != 0)
  {
    // Front vertex of Queue
    int u = q.Peek();
    q.Dequeue();
 
    inQueue[u] = false;
 
    // Relaxing all edges of
    // vertex from the Queue
    foreach (pair x in g[u])
    {
      int v = x.first;
      int cost = x.second;
 
      // Update the dist[v] to
      // minimum distance
      if (dist[v] > dist[u] + cost)
      {
        dist[v] = dist[u] + cost;
 
        // If vertex v is in Queue
        if (!inQueue[v])
        {
          q.Enqueue(v);
          inQueue[v] = true;
          cnt[v]++;
 
          // Negative cycle
          if (cnt[v] >= V)
            return true;
        }
      }
    }
  }
 
  // No cycle found
  return false;
}
 
// Driver Code
public static void Main(String[] args)
{
  // Number of vertices
  int N = 4;
 
  // Given source node src
  int src = 0;
 
  // Number of Edges
  int M = 4;
 
  // Given Edges with weight
  int [,]Edges = {{0, 1, 1},
                  {1, 2, -1},
                  {2, 3, -1},
                  {3, 0, -1}};
 
  // If cycle is present
  if (sfpa(N, src, Edges, M) == true)
    Console.Write("Yes" + "\n");
  else
    Console.Write("No" + "\n");
}
}
 
// This code is contributed by 29AjayKumar


Javascript


输出:
Yes

时间复杂度: O(N*M),其中 N 是顶点数,M 是边数。
辅助空间: O(N + M)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程