Las componentes conexas son grupos de vértices que están unidos por algún camino entre sí. Dividen al grafo en “islas”: dentro de una isla puedes ir de cualquier nodo a otro, pero entre islas no hay ruta. Identificarlas ayuda a saber si el grafo está conectado, cuántas islas tiene y a concentrar cálculos o recorridos solo donde hace falta.
Una componente conexa es el grupo más grande posible de vértices donde cualquier pareja se puede alcanzar siguiendo las aristas en algún sentido. Si agregas un vértice de fuera, esa propiedad se rompe. En grafos dirigidos la idea cambia: allí importan los sentidos de las aristas y se definen las componentes fuertemente conexas, que se estudian aparte.
Abrir visualizador de componentes
En grafos no dirigidos, cada componente es una isla de conectividad: dentro de ella todos se alcanzan, fuera no hay puente. Si empiezas un recorrido (BFS o DFS) en un vértice no visitado, ese mismo proceso pinta todos los nodos de su isla y te deja listos para saltar a la siguiente.
Para hallar todas las componentes con BFS, arrancas desde un vértice no visitado, exploras en anchura y marcas a todos los que alcanzas con el mismo identificador. Cuando la cola queda vacía, esa componente está completa; luego eliges otro vértice sin marcar y repites. Cada ejecución de BFS corresponde a una componente distinta.
El procedimiento es análogo usando DFS; la pila (explícita o recursiva) marca los vértices de la componente actual.
#include <stdio.h>
#include <stdlib.h>
typedef struct Arista {
int destino;
struct Arista *sig;
} Arista;
typedef struct {
int n;
Arista **listas;
} Grafo;
void agregar(Grafo *g, int u, int v) {
Arista *a = malloc(sizeof(Arista));
a->destino = v;
a->sig = g->listas[u];
g->listas[u] = a;
Arista *b = malloc(sizeof(Arista));
b->destino = u;
b->sig = g->listas[v];
g->listas[v] = b;
}
void dfsComp(const Grafo *g, int u, int *visitado, int compId, int *componentes) {
visitado[u] = 1;
componentes[u] = compId;
for (Arista *it = g->listas[u]; it; it = it->sig) {
int v = it->destino;
if (!visitado[v]) dfsComp(g, v, visitado, compId, componentes);
}
}
int main(void) {
int n = 6;
Grafo g = {0};
g.n = n;
g.listas = calloc(n, sizeof(Arista *));
agregar(&g, 0, 1);
agregar(&g, 1, 2);
agregar(&g, 3, 4);
int *visitado = calloc(n, sizeof(int));
int *componentes = calloc(n, sizeof(int));
int compId = 0;
for (int u = 0; u < n; u++) {
if (!visitado[u]) {
dfsComp(&g, u, visitado, compId, componentes);
compId++;
}
}
printf("Cantidad de componentes: %d\n", compId);
for (int u = 0; u < n; u++) {
printf("Vertice %d -> componente %d\n", u, componentes[u]);
}
for (int u = 0; u < n; u++) {
Arista *it = g.listas[u];
while (it) {
Arista *tmp = it;
it = it->sig;
free(tmp);
}
}
free(g.listas);
free(visitado);
free(componentes);
return 0;
}
Al almacenar el arreglo componentes[u] puedes:
componentes[u] == componentes[v] implica conectividad.