Algoritmo de Tarjan para encontrar componentes fuertemente conectados

Un grafo dirigido es fuertemente conexo si existe un camino entre todos los pares de vértices. Un componente fuertemente conectado ( SCC ) de un gráfico dirigido es un subgrafo máximo fuertemente conectado. Por ejemplo, hay 3 SCC en el siguiente gráfico.

SCC

Hemos discutido el algoritmo de Kosaraju para componentes fuertemente conectados . El algoritmo discutido anteriormente requiere dos recorridos DFS de un gráfico. En esta publicación, se analiza el algoritmo de Tarjan que requiere solo un recorrido DFS.

El algoritmo de Tarjan se basa en los siguientes hechos: 

  1. La búsqueda DFS produce un árbol/bosque DFS 
  2. Los componentes fuertemente conectados forman subárboles del árbol DFS. 
  3. Si podemos encontrar la cabeza de dichos subárboles, podemos imprimir/almacenar todos los Nodes en ese subárbol (incluida la cabeza) y ese será un SCC. 
  4. No hay borde posterior de un SCC a otro (puede haber bordes cruzados, pero no se usarán bordes cruzados mientras se procesa el gráfico).

Para encontrar la cabeza de un SCC, calculamos el disco y la array baja (como se hizo para el punto de articulación , el puente y el componente biconectado ). Como se discutió en las publicaciones anteriores, low[u] indica el vértice visitado más temprano (el vértice con un tiempo de descubrimiento mínimo) al que se puede llegar desde un subárbol enraizado con u. Un Node u es cabeza si disco[u] = bajo[u].

La siguiente imagen es una ilustración del enfoque:  

En la figura anterior, hemos mostrado un gráfico y uno del árbol DFS (puede haber diferentes árboles DFS en el mismo gráfico según el orden en que se recorren los bordes). 

En un árbol DFS, las flechas continuas son los bordes del árbol y las flechas discontinuas son los bordes posteriores (bordes del árbol DFS  )

Los valores Disco y Bajo se muestran en la Figura para cada Node como (Disco/Bajo). 

Disco: este es el momento en que se visita un Node por primera vez durante el recorrido DFS. Para los Nodes A, B, C, .. y J en el árbol DFS, los valores de disco son 1, 2, 3, .., 10. 

Bajo: en el árbol DFS, los bordes del árbol nos llevan hacia adelante, desde el Node ancestro hasta uno de sus descendientes. Por ejemplo, desde el Node C, las aristas del árbol nos pueden llevar al Node G, al Node I, etc. Las aristas posteriores nos llevan hacia atrás, desde un Node descendiente hasta uno de sus ancestros. 

Por ejemplo, desde el Node G, los bordes posteriores nos llevan a E o C. Si observamos el árbol y el borde posterior juntos, podemos ver que si comenzamos el recorrido desde un Node, podemos descender por el árbol a través de los bordes del árbol y luego sube por los bordes traseros. Por ejemplo, desde el Node E, podemos bajar a G y luego subir a C. De manera similar, desde E, podemos bajar a I o J y luego subir a F. El valor «bajo» de un Node indica la parte superior alcanzable antepasado (con el valor de disco mínimo posible) a través del subárbol de ese Node. Entonces, para cualquier Node, un valor bajo es igual a su valor de disco de todos modos (un Node es el antepasado de sí mismo). Luego buscamos en su subárbol y vemos si hay algún Node que pueda llevarnos a alguno de sus ancestros. Si hay varios bordes posteriores en el subárbol que nos llevan a diferentes ancestros, entonces tomamos el que tiene el valor de disco mínimo (es decir, el que está más arriba). Si observamos el Node F, tiene dos subárboles. El subárbol con el Node G nos lleva a E y C. El otro subárbol nos lleva de regreso a F solamente. Aquí, el ancestro más alto es C, donde F puede alcanzar, por lo que el valor bajo de F es 3 (el valor de disco de C). 

Según la discusión anterior, debe quedar claro que los valores bajos de B, C y D son 1 (ya que A es el Node superior al que pueden llegar B, C y D). De la misma manera, los valores bajos de E, F y G son 3, y los valores bajos de H, I y J son 6.
Para cualquier Node u, cuando se inicia DFS, Low se establecerá en su Disco 1

Luego, más adelante, se realizará DFS en cada uno de sus hijos v uno por uno. El valor bajo de u puede cambiarlo en dos casos: 

  • Caso 1 (Borde del árbol): si el Node v aún no se ha visitado, luego de que se complete el DFS de v, un mínimo de low[u] y low[v] se actualizará a low[u]. 
     
  • Caso 2 (Borde posterior): cuando el niño v ya está visitado, entonces un mínimo de low[u] y Disc[v] se actualizarán a low[u]. 
     

En el caso dos, . La respuesta es NO . Si puede pensar por qué la respuesta es NO , probablemente entendió el concepto Low and Disc.

edge-types

Los mismos valores Low y Disc ayudan a resolver otros problemas gráficos como el punto de articulación , el puente y el componente biconectado .

Para rastrear el subárbol enraizado en la cabeza, podemos usar una pila (siga presionando el Node mientras visita). Cuando se encuentra un Node principal, extraiga todos los Nodes de la pila hasta que saque la cabeza de la pila.

Para asegurarnos, no consideramos los bordes cruzados, cuando llegamos a un Node que ya está visitado, debemos procesar el Node visitado solo si está presente en la pila, de lo contrario, ignorar el Node.  

A continuación se muestra la implementación del algoritmo de Tarjan para imprimir todos los SCC. 

C++

// A C++ program to find strongly connected components in a given
// directed graph using Tarjan's algorithm (single DFS)
#include<iostream>
#include <list>
#include <stack>
#define NIL -1
using namespace std;
 
// A class that represents an directed graph
class Graph
{
    int V; // No. of vertices
    list<int> *adj; // A dynamic array of adjacency lists
 
    // A Recursive DFS based function used by SCC()
    void SCCUtil(int u, int disc[], int low[],
                stack<int> *st, bool stackMember[]);
public:
    Graph(int V); // Constructor
    void addEdge(int v, int w); // function to add an edge to graph
    void SCC(); // prints strongly connected components
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}
 
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w);
}
 
// A recursive function that finds and prints strongly connected
// components using DFS traversal
// u --> The vertex to be visited next
// disc[] --> Stores discovery times of visited vertices
// low[] -- >> earliest visited vertex (the vertex with minimum
//             discovery time) that can be reached from subtree
//             rooted with current vertex
// *st -- >> To store all the connected ancestors (could be part
//         of SCC)
// stackMember[] --> bit/index array for faster check whether
//                 a node is in stack
void Graph::SCCUtil(int u, int disc[], int low[], stack<int> *st,
                    bool stackMember[])
{
    // A static variable is used for simplicity, we can avoid use
    // of static variable by passing a pointer.
    static int time = 0;
 
    // Initialize discovery time and low value
    disc[u] = low[u] = ++time;
    st->push(u);
    stackMember[u] = true;
 
    // Go through all vertices adjacent to this
    list<int>::iterator i;
    for (i = adj[u].begin(); i != adj[u].end(); ++i)
    {
        int v = *i; // v is current adjacent of 'u'
 
        // If v is not visited yet, then recur for it
        if (disc[v] == -1)
        {
            SCCUtil(v, disc, low, st, stackMember);
 
            // Check if the subtree rooted with 'v' has a
            // connection to one of the ancestors of 'u'
            // Case 1 (per above discussion on Disc and Low value)
            low[u] = min(low[u], low[v]);
        }
 
        // Update low value of 'u' only of 'v' is still in stack
        // (i.e. it's a back edge, not cross edge).
        // Case 2 (per above discussion on Disc and Low value)
        else if (stackMember[v] == true)
            low[u] = min(low[u], disc[v]);
    }
 
    // head node found, pop the stack and print an SCC
    int w = 0; // To store stack extracted vertices
    if (low[u] == disc[u])
    {
        while (st->top() != u)
        {
            w = (int) st->top();
            cout << w << " ";
            stackMember[w] = false;
            st->pop();
        }
        w = (int) st->top();
        cout << w << "\n";
        stackMember[w] = false;
        st->pop();
    }
}
 
// The function to do DFS traversal. It uses SCCUtil()
void Graph::SCC()
{
    int *disc = new int[V];
    int *low = new int[V];
    bool *stackMember = new bool[V];
    stack<int> *st = new stack<int>();
 
    // Initialize disc and low, and stackMember arrays
    for (int i = 0; i < V; i++)
    {
        disc[i] = NIL;
        low[i] = NIL;
        stackMember[i] = false;
    }
 
    // Call the recursive helper function to find strongly
    // connected components in DFS tree with vertex 'i'
    for (int i = 0; i < V; i++)
        if (disc[i] == NIL)
            SCCUtil(i, disc, low, st, stackMember);
}
 
// Driver program to test above function
int main()
{
    cout << "\nSCCs in first graph \n";
    Graph g1(5);
    g1.addEdge(1, 0);
    g1.addEdge(0, 2);
    g1.addEdge(2, 1);
    g1.addEdge(0, 3);
    g1.addEdge(3, 4);
    g1.SCC();
 
    cout << "\nSCCs in second graph \n";
    Graph g2(4);
    g2.addEdge(0, 1);
    g2.addEdge(1, 2);
    g2.addEdge(2, 3);
    g2.SCC();
 
    cout << "\nSCCs in third graph \n";
    Graph g3(7);
    g3.addEdge(0, 1);
    g3.addEdge(1, 2);
    g3.addEdge(2, 0);
    g3.addEdge(1, 3);
    g3.addEdge(1, 4);
    g3.addEdge(1, 6);
    g3.addEdge(3, 5);
    g3.addEdge(4, 5);
    g3.SCC();
 
    cout << "\nSCCs in fourth graph \n";
    Graph g4(11);
    g4.addEdge(0,1);g4.addEdge(0,3);
    g4.addEdge(1,2);g4.addEdge(1,4);
    g4.addEdge(2,0);g4.addEdge(2,6);
    g4.addEdge(3,2);
    g4.addEdge(4,5);g4.addEdge(4,6);
    g4.addEdge(5,6);g4.addEdge(5,7);g4.addEdge(5,8);g4.addEdge(5,9);
    g4.addEdge(6,4);
    g4.addEdge(7,9);
    g4.addEdge(8,9);
    g4.addEdge(9,8);
    g4.SCC();
 
    cout << "\nSCCs in fifth graph \n";
    Graph g5(5);
    g5.addEdge(0,1);
    g5.addEdge(1,2);
    g5.addEdge(2,3);
    g5.addEdge(2,4);
    g5.addEdge(3,0);
    g5.addEdge(4,2);
    g5.SCC();
 
    return 0;
}

Java

// Java program to find strongly connected
// components in a given directed graph
// using Tarjan's algorithm (single DFS)
import java.io.*;
import java.util.*;
 
// This class represents a directed graph
// using adjacency list representation
class Graph{
 
// No. of vertices   
private int V;
 
//Adjacency Lists
private LinkedList<Integer> adj[];
private int Time;
 
// Constructor
@SuppressWarnings("unchecked")
Graph(int v)
{
    V = v;
    adj = new LinkedList[v];
     
    for(int i = 0; i < v; ++i)
        adj[i] = new LinkedList();
         
    Time = 0;
}
 
// Function to add an edge into the graph
void addEdge(int v,int w)
{
    adj[v].add(w);
}
 
// A recursive function that finds and prints strongly
// connected components using DFS traversal
// u --> The vertex to be visited next
// disc[] --> Stores discovery times of visited vertices
// low[] -- >> earliest visited vertex (the vertex with
//             minimum discovery time) that can be reached
//             from subtree rooted with current vertex
// st -- >> To store all the connected ancestors (could be part
//         of SCC)
// stackMember[] --> bit/index array for faster check
//                   whether a node is in stack
void SCCUtil(int u, int low[], int disc[],
             boolean stackMember[],
             Stack<Integer> st)
{
     
    // Initialize discovery time and low value
    disc[u] = Time;
    low[u] = Time;
    Time += 1;
    stackMember[u] = true;
    st.push(u);
 
    int n;
     
    // Go through all vertices adjacent to this
    Iterator<Integer> i = adj[u].iterator();
     
    while (i.hasNext())
    {
        n = i.next();
         
        if (disc[n] == -1)
        {
            SCCUtil(n, low, disc, stackMember, st);
             
            // Check if the subtree rooted with v
            // has a connection to one of the
            // ancestors of u
            // Case 1 (per above discussion on
            // Disc and Low value)
            low[u] = Math.min(low[u], low[n]);
        }
        else if (stackMember[n] == true)
        {
             
            // Update low value of 'u' only if 'v' is
            // still in stack (i.e. it's a back edge,
            // not cross edge).
            // Case 2 (per above discussion on Disc
            // and Low value)
            low[u] = Math.min(low[u], disc[n]);
        }
    }
 
    // head node found, pop the stack and print an SCC
    // To store stack extracted vertices
    int w = -1;
    if (low[u] == disc[u])
    {
        while (w != u)
        {
            w = (int)st.pop();
            System.out.print(w + " ");
            stackMember[w] = false;
        }
        System.out.println();
    }
}
 
// The function to do DFS traversal.
// It uses SCCUtil()
void SCC()
{
     
    // Mark all the vertices as not visited
    // and Initialize parent and visited,
    // and ap(articulation point) arrays
    int disc[] = new int[V];
    int low[] = new int[V];
    for(int i = 0;i < V; i++)
    {
        disc[i] = -1;
        low[i] = -1;
    }
     
    boolean stackMember[] = new boolean[V];
    Stack<Integer> st = new Stack<Integer>();
     
    // Call the recursive helper function
    // to find articulation points
    // in DFS tree rooted with vertex 'i'
    for(int i = 0; i < V; i++)
    {
        if (disc[i] == -1)
            SCCUtil(i, low, disc,
                    stackMember, st);
    }
}
 
// Driver code
public static void main(String args[])
{
     
    // Create a graph given in the above diagram
    Graph g1 = new Graph(5);
 
    g1.addEdge(1, 0);
    g1.addEdge(0, 2);
    g1.addEdge(2, 1);
    g1.addEdge(0, 3);
    g1.addEdge(3, 4);
    System.out.println("SSC in first graph ");
    g1.SCC();
 
    Graph g2 = new Graph(4);
    g2.addEdge(0, 1);
    g2.addEdge(1, 2);
    g2.addEdge(2, 3);
    System.out.println("\nSSC in second graph ");
    g2.SCC();
     
    Graph g3 = new Graph(7);
    g3.addEdge(0, 1);
    g3.addEdge(1, 2);
    g3.addEdge(2, 0);
    g3.addEdge(1, 3);
    g3.addEdge(1, 4);
    g3.addEdge(1, 6);
    g3.addEdge(3, 5);
    g3.addEdge(4, 5);
    System.out.println("\nSSC in third graph ");
    g3.SCC();
     
    Graph g4 = new Graph(11);
    g4.addEdge(0, 1);
    g4.addEdge(0, 3);
    g4.addEdge(1, 2);
    g4.addEdge(1, 4);
    g4.addEdge(2, 0);
    g4.addEdge(2, 6);
    g4.addEdge(3, 2);
    g4.addEdge(4, 5);
    g4.addEdge(4, 6);
    g4.addEdge(5, 6);
    g4.addEdge(5, 7);
    g4.addEdge(5, 8);
    g4.addEdge(5, 9);
    g4.addEdge(6, 4);
    g4.addEdge(7, 9);
    g4.addEdge(8, 9);
    g4.addEdge(9, 8);
    System.out.println("\nSSC in fourth graph ");
    g4.SCC();
     
    Graph g5 = new Graph (5);
    g5.addEdge(0, 1);
    g5.addEdge(1, 2);
    g5.addEdge(2, 3);
    g5.addEdge(2, 4);
    g5.addEdge(3, 0);
    g5.addEdge(4, 2);
    System.out.println("\nSSC in fifth graph ");
    g5.SCC();
}
}
 
// This code is contributed by
// Prateek Gupta (@prateekgupta10)

Python3

# Python program to find strongly connected components in a given
# directed graph using Tarjan's algorithm (single DFS)
#Complexity : O(V+E)
  
from collections import defaultdict
  
#This class represents an directed graph
# using adjacency list representation
class Graph:
  
    def __init__(self,vertices):
        #No. of vertices
        self.V= vertices
         
        # default dictionary to store graph
        self.graph = defaultdict(list)
         
        self.Time = 0
  
    # function to add an edge to graph
    def addEdge(self,u,v):
        self.graph[u].append(v)
         
  
    '''A recursive function that find finds and prints strongly connected
    components using DFS traversal
    u --> The vertex to be visited next
    disc[] --> Stores discovery times of visited vertices
    low[] -- >> earliest visited vertex (the vertex with minimum
                discovery time) that can be reached from subtree
                rooted with current vertex
     st -- >> To store all the connected ancestors (could be part
           of SCC)
     stackMember[] --> bit/index array for faster check whether
                  a node is in stack
    '''
    def SCCUtil(self,u, low, disc, stackMember, st):
 
        # Initialize discovery time and low value
        disc[u] = self.Time
        low[u] = self.Time
        self.Time += 1
        stackMember[u] = True
        st.append(u)
 
        # Go through all vertices adjacent to this
        for v in self.graph[u]:
             
            # If v is not visited yet, then recur for it
            if disc[v] == -1 :
             
                self.SCCUtil(v, low, disc, stackMember, st)
 
                # Check if the subtree rooted with v has a connection to
                # one of the ancestors of u
                # Case 1 (per above discussion on Disc and Low value)
                low[u] = min(low[u], low[v])
                         
            elif stackMember[v] == True:
 
                '''Update low value of 'u' only if 'v' is still in stack
                (i.e. it's a back edge, not cross edge).
                Case 2 (per above discussion on Disc and Low value) '''
                low[u] = min(low[u], disc[v])
 
        # head node found, pop the stack and print an SCC
        w = -1 #To store stack extracted vertices
        if low[u] == disc[u]:
            while w != u:
                w = st.pop()
                print (w, end=" ")
                stackMember[w] = False
                 
            print()
             
     
 
    #The function to do DFS traversal.
    # It uses recursive SCCUtil()
    def SCC(self):
  
        # Mark all the vertices as not visited
        # and Initialize parent and visited,
        # and ap(articulation point) arrays
        disc = [-1] * (self.V)
        low = [-1] * (self.V)
        stackMember = [False] * (self.V)
        st =[]
         
 
        # Call the recursive helper function
        # to find articulation points
        # in DFS tree rooted with vertex 'i'
        for i in range(self.V):
            if disc[i] == -1:
                self.SCCUtil(i, low, disc, stackMember, st)
 
 
  
  
  
# Create a graph given in the above diagram
g1 = Graph(5)
g1.addEdge(1, 0)
g1.addEdge(0, 2)
g1.addEdge(2, 1)
g1.addEdge(0, 3)
g1.addEdge(3, 4)
print ("SSC in first graph ")
g1.SCC()
 
g2 = Graph(4)
g2.addEdge(0, 1)
g2.addEdge(1, 2)
g2.addEdge(2, 3)
print ("nSSC in second graph ")
g2.SCC()
 
  
g3 = Graph(7)
g3.addEdge(0, 1)
g3.addEdge(1, 2)
g3.addEdge(2, 0)
g3.addEdge(1, 3)
g3.addEdge(1, 4)
g3.addEdge(1, 6)
g3.addEdge(3, 5)
g3.addEdge(4, 5)
print ("nSSC in third graph ")
g3.SCC()
 
g4 = Graph(11)
g4.addEdge(0, 1)
g4.addEdge(0, 3)
g4.addEdge(1, 2)
g4.addEdge(1, 4)
g4.addEdge(2, 0)
g4.addEdge(2, 6)
g4.addEdge(3, 2)
g4.addEdge(4, 5)
g4.addEdge(4, 6)
g4.addEdge(5, 6)
g4.addEdge(5, 7)
g4.addEdge(5, 8)
g4.addEdge(5, 9)
g4.addEdge(6, 4)
g4.addEdge(7, 9)
g4.addEdge(8, 9)
g4.addEdge(9, 8)
print ("nSSC in fourth graph ")
g4.SCC();
 
 
g5 = Graph (5)
g5.addEdge(0, 1)
g5.addEdge(1, 2)
g5.addEdge(2, 3)
g5.addEdge(2, 4)
g5.addEdge(3, 0)
g5.addEdge(4, 2)
print ("nSSC in fifth graph ")
g5.SCC();
 
#This code is contributed by Neelam Yadav

Javascript

<script>
 
// Javascript program to find strongly connected
// components in a given directed graph
// using Tarjan's algorithm (single DFS)
 
// This class represents a directed graph
// using adjacency list representation
class Graph{
     
// Constructor
constructor(v)
{
    this.V = v;
    this.adj = new Array(v);
   
    for(let i = 0; i < v; ++i)
        this.adj[i] = [];
       
    this.Time = 0;
}
 
// Function to add an edge into the graph
addEdge(v, w)
{
    this.adj[v].push(w);
}
 
// A recursive function that finds and prints strongly
// connected components using DFS traversal
// u --> The vertex to be visited next
// disc[] --> Stores discovery times of visited vertices
// low[] -- >> earliest visited vertex (the vertex with
//             minimum discovery time) that can be reached
//             from subtree rooted with current vertex
// st -- >> To store all the connected ancestors (could be
//          part of SCC)
// stackMember[] --> bit/index array for faster check
//                   whether a node is in stack
SCCUtil(u, low, disc, stackMember, st)
{
     
    // Initialize discovery time and low value
    disc[u] = this.Time;
    low[u] = this.Time;
    this.Time += 1;
    stackMember[u] = true;
    st.push(u);
   
    let n;
       
    // Go through all vertices adjacent to this
    for(let i of this.adj[u])
    {
        n = i;
           
        if (disc[n] == -1)
        {
            this.SCCUtil(n, low, disc, stackMember, st);
               
            // Check if the subtree rooted with v
            // has a connection to one of the
            // ancestors of u
            // Case 1 (per above discussion on
            // Disc and Low value)
            low[u] = Math.min(low[u], low[n]);
        }
        else if (stackMember[n] == true)
        {
               
            // Update low value of 'u' only if 'v' is
            // still in stack (i.e. it's a back edge,
            // not cross edge).
            // Case 2 (per above discussion on Disc
            // and Low value)
            low[u] = Math.min(low[u], disc[n]);
        }
    }
   
    // Head node found, pop the stack and print an SCC
    // To store stack extracted vertices
    let w = -1;
    if (low[u] == disc[u])
    {
        while (w != u)
        {
            w = st.pop();
            document.write(w + " ");
            stackMember[w] = false;
        }
        document.write("<br>");
    }
    }
     
// The function to do DFS traversal.
// It uses SCCUtil()
SCC()
{
     
    // Mark all the vertices as not visited
    // and Initialize parent and visited,
    // and ap(articulation point) arrays
    let disc = new Array(this.V);
    let low = new Array(this.V);
    for(let i = 0;i < this.V; i++)
    {
        disc[i] = -1;
        low[i] = -1;
    }
       
    let stackMember = new Array(this.V);
    let st = [];
       
    // Call the recursive helper function
    // to find articulation points
    // in DFS tree rooted with vertex 'i'
    for(let i = 0; i < this.V; i++)
    {
        if (disc[i] == -1)
            this.SCCUtil(i, low, disc,
                         stackMember, st);
    }
}
}
 
// Driver code
 
// Create a graph given in the above diagram
let g1 = new Graph(5);
 
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
document.write("SSC in first graph <br>");
g1.SCC();
 
let g2 = new Graph(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
document.write("\nSSC in second graph<br> ");
g2.SCC();
 
let g3 = new Graph(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
document.write("\nSSC in third graph <br>");
g3.SCC();
 
let g4 = new Graph(11);
g4.addEdge(0, 1);
g4.addEdge(0, 3);
g4.addEdge(1, 2);
g4.addEdge(1, 4);
g4.addEdge(2, 0);
g4.addEdge(2, 6);
g4.addEdge(3, 2);
g4.addEdge(4, 5);
g4.addEdge(4, 6);
g4.addEdge(5, 6);
g4.addEdge(5, 7);
g4.addEdge(5, 8);
g4.addEdge(5, 9);
g4.addEdge(6, 4);
g4.addEdge(7, 9);
g4.addEdge(8, 9);
g4.addEdge(9, 8);
document.write("\nSSC in fourth graph<br> ");
g4.SCC();
 
let g5 = new Graph (5);
g5.addEdge(0, 1);
g5.addEdge(1, 2);
g5.addEdge(2, 3);
g5.addEdge(2, 4);
g5.addEdge(3, 0);
g5.addEdge(4, 2);
document.write("\nSSC in fifth graph <br>");
g5.SCC();
 
// This code is contributed by avanitrachhadiya2155
 
</script>
Producción

SCCs in first graph 
4
3
1 2 0

SCCs in second graph 
3
2
1
0

SCCs in third graph 
5
3
4
6
2 1 0

SCCs in fourth graph 
8 9
7
5 4 6
3 2 1 0
10

SCCs in fifth graph 
4 3 2 1 0

Complejidad de tiempo: el algoritmo anterior llama principalmente a DFS, DFS toma O (V + E) para un gráfico representado mediante una lista de adyacencia. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *