Componente puternic conectate

Componente puternic conectate

Componente puternic conectate (SCC) sunt un concept fundamental în teoria grafurilor și algoritmi. Într-un grafic direcționat, a Componentă puternic conectată este un subset de vârfuri în care fiecare vârf din submulțime este accesibil de la orice alt vârf din aceeași submulțime prin parcurgerea muchiilor direcționate. Găsirea SCC-uri a unui grafic poate oferi perspective importante asupra structurii și conectivității graficului, cu aplicații în diverse domenii, cum ar fi analiza rețelelor sociale, accesarea cu crawlere web și rutarea rețelei . Acest tutorial va explora definiția, proprietățile și algoritmii eficienți pentru identificarea componentelor puternic conectate în structurile de date grafice

Cuprins

Ce este Componentele Strongly Connected (SCC)?

A componentă puternic conectată a unui graf direcționat este un subgraf maxim în care fiecare pereche de vârfuri este reciproc accesibilă. Aceasta înseamnă că pentru oricare două noduri A și B din acest subgraf, există o cale de la A la B și o cale de la B la A.



De exemplu: Graficul de mai jos are două componente puternic conectate {1,2,3,4} și {5,6,7}, deoarece există o cale de la fiecare vârf la fiecare alt vârf în aceeași componentă puternic conectată.

scc_fianldrawio

Componentă puternic conectată

De ce sunt importante componentele puternic conectate (SCC)?

Înțelegerea SCC-urilor este crucială pentru diverse aplicații, cum ar fi:

  • Analiza rețelei : Identificarea clusterelor de noduri strâns interconectate.
  • Optimizarea crawlerelor web : determinarea unor părți ale graficului web care sunt strâns legate.
  • Rezolvarea dependenței : În software, înțelegerea care module sunt interdependente.

Diferența dintre componentele conectate și cele puternic conectate ( SCC)

Conectivitate în a grafic nedirecţionat se referă la dacă două vârfuri sunt accesibile unul de celălalt sau nu. Se spune că două vârfuri sunt conectate dacă există o cale între ele. Între timp Puternic conectat este aplicabil numai pentru grafice dirijate . Un subgraf al unui graf direcționat este considerat a fi un Componente puternic conectate (SCC) dacă și numai dacă pentru fiecare pereche de vârfuri A și B , există o cale de la A la B si o cale de la B la A . Să vedem de ce metoda standard dfs pentru a găsi componentele conectate într-un grafic nu poate fi folosit pentru a determina componente puternic conectate.

Luați în considerare următorul grafic:

scc_fianldrawio

Acum, să începem a dfs apel de la vârful 1 pentru a vizita alte vârfuri.

dfs_finaldrawio

De ce metoda DFS convențională nu poate fi folosită pentru a găsi componentele puternic conectate?

Toate vârfurile pot fi atinse de la vârful 1. Dar vârfurile 1 și 5,6,7 nu pot fi în aceeași componentă puternic conectată deoarece nu există o cale direcționată de la vârful 5,6 sau 7 la vârful 1. Graficul are două puncte puternice. componentele conectate {1,2,3,4} și {5,6,7}. Deci metoda convențională dfs nu poate fi folosită pentru a găsi componentele puternic conectate.

Conectarea a două componente puternic conectate printr-o margine unidirecțională

Două componente conectate diferite devin o singură componentă dacă se adaugă o muchie între un vârf de la o componentă la un vârf al altei componente. Dar nu este cazul componentelor puternic conectate. Două componente puternic conectate nu devin o singură componentă puternic conectată dacă există doar o margine unidirecțională de la un SCC la altul SCC.

unidrawio-(2)

Abordarea forței brute pentru găsirea de componente puternic conectate

Metoda simplă va fi pentru fiecare vârf i (care nu face parte din nicio componentă puternică) găsiți vârfurile care vor fi partea componentei puternic conectate care conține vârful i. Două vârfuri i și j vor fi în aceeași componentă puternic conectată dacă există o cale direcționată de la vârful i la vârful j și invers.

Să înțelegem abordarea cu ajutorul următorului exemplu:

desen exemplu

  • Începând cu vârful 1. Există o cale de la vârful 1 la vârful 2 și invers. În mod similar, există o cale de la vârful 1 la vârful 3 și invers. Deci, vârfurile 2 și 3 vor fi în aceeași componentă puternic conectată ca vârful 1. Deși există o cale direcționată de la vârful 1 la vârful 4 și vârful 5. Dar nu există o cale direcționată de la vârful 4,5 la vârful 1, deci vârful 4 iar 5 nu va fi în aceeași componentă puternic conectată ca vârful 1. Astfel, vârfurile 1,2 și 3 formează o componentă puternic conectată.
  • Pentru Vertex 2 și 3, Componenta puternic conectată a fost deja determinată.
  • Pentru vârful 4, există o cale de la vârful 4 la vârful 5, dar nu există o cale de la vârful 5 la vârful 4. Deci vârfurile 4 și 5 nu vor fi în aceeași componentă puternic conectată. Deci, atât Vertex 4, cât și Vertex 5 vor face parte din Componenta Single Strongly Connected.
  • Prin urmare, vor exista 3 componente puternic conectate {1,2,3}, {4} și {5}.

Mai jos este implementarea abordării de mai sus:

C++
#include  using namespace std; class GFG { public:  // dfs Function to reach destination  bool dfs(int curr, int des, vector >& adj, vector & vis) { // Dacă nodul curr este destinația return true if (curr == des) { return true;  } vis[curr] = 1;  for (auto x : adj[curr]) { if (!vis[x]) { if (dfs(x, des, adj, vis)) { return true;  } } } return false;  } // Pentru a spune dacă există o cale de la sursă la // destinație bool isPath(int src, int des, vector >& adj) { vector vis(adj.size() + 1, 0);  return dfs(src, des, adj, vis);  } // Funcție pentru a returna toată // componenta puternic conectată a unui grafic.  vector > findSCC(int n, vector >& a) { // Stochează toate componentele puternic conectate.  vector > ans;  // Stochează dacă un vârf este o parte a oricărui vector Componentă puternic // conectată is_scc(n + 1, 0);  vector > adj(n + 1);  pentru (int i = 0; i < a.size(); i++) {  adj[a[i][0]].push_back(a[i][1]);  }  // Traversing all the vertices  for (int i = 1; i  <= n; i++) {  if (!is_scc[i]) {  // If a vertex i is not a part of any SCC  // insert it into a new SCC list and check  // for other vertices whether they can be  // thr part of thidl ist.  vector scc;  scc.push_back(i);  pentru (int j = i + 1; j <= n; j++) {  // If there is a path from vertex i to  // vertex j and vice versa put vertex j  // into the current SCC list.  if (!is_scc[j] && isPath(i, j, adj)  && isPath(j, i, adj)) {  is_scc[j] = 1;  scc.push_back(j);  }  }  // Insert the SCC containing vertex i into  // the final list.  ans.push_back(scc);  }  }  return ans;  } }; // Driver Code Starts int main() {  GFG obj;  int V = 5;  vector > muchii{ { 1, 3 }, { 1, 4 }, { 2, 1 }, { 3, 2 }, { 4, 5 } };  vector > ans = obj.findSCC(V, margini);  cout < < 'Strongly Connected Components are:
';  for (auto x : ans) {  for (auto y : x) {  cout  < < y  < < ' ';  }  cout  < < '
';  } } 
Java
import java.util.ArrayList; import java.util.List; class GFG {  // dfs Function to reach destination  boolean dfs(int curr, int des, List > adj, Listă vis) { // Dacă nodul curr este destinația return true if (curr == des) { return true;  } vis.set(curr, 1);  for (int x : adj.get(curr)) { if (vis.get(x) == 0) { if (dfs(x, des, adj, vis)) { return true;  } } } return false;  } // Pentru a spune dacă există o cale de la sursă la // destinație boolean isPath(int src, int des, List > adj) { Listă vis = new ArrayList(adj.size() + 1);  pentru (int i = 0; i <= adj.size(); i++) {  vis.add(0);  }  return dfs(src, des, adj, vis);  }  // Function to return all the strongly connected  // component of a graph.  List > findSCC(int n, List > a) { // Stochează toate componentele puternic conectate.  Listă > ans = new ArrayList();  // Stochează dacă un vârf face parte dintr-o listă de componente puternic // conectată is_scc = new ArrayList(n + 1);  pentru (int i = 0; i <= n; i++) {  is_scc.add(0);  }  List > adj = new ArrayList();  pentru (int i = 0; i <= n; i++) {  adj.add(new ArrayList());  }  for (List edge : a) { adj.get(edge.get(0)).add(edge.get(1));  } // Parcurgerea tuturor vârfurilor pentru (int i = 1; i <= n; i++) {  if (is_scc.get(i) == 0) {  // If a vertex i is not a part of any SCC  // insert it into a new SCC list and check  // for other vertices whether they can be  // the part of this list.  List scc = new ArrayList();  scc.add(i);  pentru (int j = i + 1; j <= n; j++) {  // If there is a path from vertex i to  // vertex j and vice versa, put vertex j  // into the current SCC list.  if (is_scc.get(j) == 0 && isPath(i, j, adj)  && isPath(j, i, adj)) {  is_scc.set(j, 1);  scc.add(j);  }  }  // Insert the SCC containing vertex i into  // the final list.  ans.add(scc);  }  }  return ans;  } } public class Main {  public static void main(String[] args) {  GFG obj = new GFG();  int V = 5;  List > margini = new ArrayList();  edges.add(new ArrayList(Lista.of(1, 3)));  edges.add(new ArrayList(Lista.of(1, 4)));  edges.add(new ArrayList(Lista.of(2, 1)));  edges.add(new ArrayList(Lista.of(3, 2)));  edges.add(new ArrayList(Lista.of(4, 5)));  Listă > ans = obj.findSCC(V, margini);  System.out.println('Componentele puternic conectate sunt:');  pentru (Lista x : ans) { for (int y : x) { System.out.print(y + ' ');  } System.out.println();  } } } // Acest cod este contribuit de shivamgupta310570>> Piton   C#   
using System; using System.Collections.Generic; class GFG {  // dfs Function to reach destination  public bool Dfs(int curr, int des, List > adj, Listă vis) { // Dacă nodul curr este destinația, returnează adevărat dacă (curr == des) { returnează adevărat;  } vis[curr] = 1;  foreach (var x in adj[curr]) { if (vis[x] == 0) { if (Dfs(x, des, adj, vis)) { return true;  } } } return false;  } // Pentru a spune dacă există o cale de la sursă la destinație public bool IsPath(int src, int des, List > adj) { var show = listă nouă (adj.Număr + 1);  pentru (int i = 0; i < adj.Count + 1; i++)  {  vis.Add(0);  }  return Dfs(src, des, adj, vis);  }  // Function to return all the strongly connected components of a graph  public List > FindSCC(int n, List > a) { // Stochează toate componentele puternic conectate var ans = listă nouă >();  // Stochează dacă un vârf face parte dintr-o componentă puternic conectată var isScc = listă nouă (n + 1);  pentru (int i = 0; i < n + 1; i++)  {  isScc.Add(0);  }  var adj = new List >(n + 1);  pentru (int i = 0; i < n + 1; i++)  {  adj.Add(new List ());  } pentru (int i = 0; i < a.Count; i++)  {  adj[a[i][0]].Add(a[i][1]);  }  // Traversing all the vertices  for (int i = 1; i  <= n; i++)  {  if (isScc[i] == 0)  {  // If a vertex i is not a part of any SCC  // insert it into a new SCC list and check  // for other vertices whether they can be  // the part of this list.  var scc = new List ();  scc.Add(i);  pentru (int j = i + 1; j <= n; j++)  {  // If there is a path from vertex i to  // vertex j and vice versa, put vertex j  // into the current SCC list.  if (isScc[j] == 0 && IsPath(i, j, adj) && IsPath(j, i, adj))  {  isScc[j] = 1;  scc.Add(j);  }  }  // Insert the SCC containing vertex i into  // the final list.  ans.Add(scc);  }  }  return ans;  } } // Driver Code Starts class Program {  static void Main(string[] args)  {  GFG obj = new GFG();  int V = 5;  List > margini = Listă nouă > { Listă nouă { 1, 3 }, listă nouă { 1, 4 }, listă nouă { 2, 1 }, listă nouă { 3, 2 }, listă nouă { 4, 5 } };  Listă > ans = obj.FindSCC(V, edges);  Console.WriteLine('Componentele puternic conectate sunt:');  foreach (var x in ans) { foreach (var y in x) { Consola.Scrie(y + ' ');  } Console.WriteLine();  } } } // Acest cod este contribuit de shivamgupta310570>> Javascript     
Ieșire
Strongly Connected Components are: 1 2 3 4 5 

Complexitatea timpului: O(n * (n + m)), deoarece pentru fiecare pereche de vârfuri verificăm dacă există o cale între ele.
Spațiu auxiliar: O(N)

Abordare eficientă pentru găsirea de componente puternic conectate (SCC)

Pentru a găsi SCC-uri într-un grafic, putem folosi algoritmi precum Algoritmul lui Kosaraju sau Algoritmul lui Tarjan . Să explorăm acești algoritmi pas cu pas.

1. Algoritmul lui Kosaraju :

Algoritmul lui Kosaraju implică două faze principale:

  1. Efectuarea căutării în profunzime (DFS) pe graficul original :
    • Mai întâi facem un DFS pe graficul original și înregistrăm timpii de terminare a nodurilor (adică, momentul la care DFS termină explorarea completă a unui nod).
  2. Efectuarea DFS pe graficul transpus :
    • Apoi inversăm direcția tuturor muchiilor din grafic pentru a crea graficul transpus.
    • În continuare, efectuăm un DFS pe graficul transpus, luând în considerare nodurile în ordinea descrescătoare a timpilor lor de sfârșit înregistrați în prima fază.
    • Fiecare traversare DFS în această fază ne va oferi un SCC.

Iată o versiune simplificată a algoritmului lui Kosaraju:

  1. DFS pe graficul original : Înregistrați timpii de terminare.
  2. Transpuneți graficul : inversează toate marginile.
  3. DFS pe graficul transpus : Procesează nodurile în ordinea descrescătoare a timpilor de terminare pentru a găsi SCC-uri.

2. Algoritmul lui Tarjan :

Algoritmul lui Tarjan este mai eficient deoarece găsește SCC-uri într-o singură trecere DFS folosind o stivă și o contabilitate suplimentară:

  1. Traversare DFS : În timpul DFS, mențineți un index pentru fiecare nod și cel mai mic index (valoare low-link) la care se poate ajunge din nod.
  2. Grămadă : Țineți evidența nodurilor aflate în prezent în stiva de recursivitate (o parte a SCC-ului curent în curs de explorare).
  3. Identificarea SCC-urilor : Când valoarea low-link a unui nod este egală cu indicele său, înseamnă că am găsit un SCC. Scoateți toate nodurile din stivă până ajungem la nodul curent.

Iată o schiță simplificată a algoritmului lui Tarjan:

  1. Inițializați index> la 0.
  2. Pentru fiecare nod nevizitat, executați DFS.
    • Setați indexul nodului și valoarea low-link.
    • Împingeți nodul pe stivă.
    • Pentru fiecare nod adiacent, fie efectuați DFS dacă nu este vizitat, fie actualizați valoarea low-link dacă se află în stivă.
    • Dacă valoarea low-link a nodului este egală cu indicele său, scoateți nodurile din stivă pentru a forma un SCC.

Concluzie

Înțelegerea și găsirea componente puternic conectate într-un grafic direcționat este esențial pentru multe aplicații în informatică. a lui Kosaraju și a lui Tarjan algoritmii sunt modalități eficiente de a identifica SCC, fiecare cu propria abordare și avantaje. Prin stăpânirea acestor concepte, puteți analiza și optimiza mai bine structura și comportamentul rețelelor complexe.



Top Articole

Categorie

Articole Interesante