Herramientas de usuario

Herramientas del sitio


algoritmos-oia:grafos:componentes-conexas

¡Esta es una revisión vieja del documento!


Componentes conexas

Definición y propiedades

Recordamos la definición de componente conexa. Dado un grafo $G$ no dirigido, una componente conexa es un conjunto de nodos maximal de $G$ tal para cada par de nodos de la componente hay un camino que los une. Con maximal queremos decir que no se le puede agregar ningun nodo más a la componente.

Decir que para cualquier par de nodos hay un camino que los une, es equivalente a que de un nodo $v_0$ en particular se pueda llegar a cualquier otro por medio de caminos. Es claro que la primera implica la segunda. Para ver que la segunda implica la primera, tomamos $u$ y $w$ nodos cualquiera de la componente, queremos ver que hay un camino que une $u$ con $w$. Pero hay un camino que une $u$ con $v_0$ y uno que une $v_0$ con $w$, luego, uniendo estos dos caminos conseguimos uno de $u$ a $w$.

Esto nos dice que la componente conexa de un nodo $v$ son los nodos desde los que se puede llegar a partir de $v$. Por lo que cada nodo pertenece a una sola componente conexa. Es decir, las componentes conexas parten a los nodos de $G$ en conjuntos sin elementos en común.

Algoritmo para hallarlas

La última observación nos dice cómo podemos hallar las componentes conexas de un grafo $G$. Simplemente para cada nodo $v$ buscamos todos los nodos a los que se puede llegar a partir de $v$. Esto se puede hacer lanzando un DFS a partir de $v$. Los nodos a los que alcance el DFS serán la componente conexa de $v$. Para no repetir componentes, podemos guardar para qué nodos ya encontramos su componente y para ellos no lanzar el DFS.

Este es un posible algoritmo, lo que hacemos es numerar las componentes en el orden que las encontramos y devoler un vector que nos dice para cada nodo a qué componente pertenece:

void dfs(int nodo, vector<vector<int>> grafo, vector<int> componente, int componenteActual) {
    // agregamos el nodo a la componente
    componente[nodo] = componenteActual;
    for(int: vecino in grafo[nodo]) {
        if(componente[vecino] != componenteActual) {
            dfs(vecino, grafo, componente, componenteActual);
        }
    }
}
 
vector<vector<int>> hallarComponentesConexas(vector<vector<int>>& grafo) {
    int n = grafo.size();
    // vector que guarda a qué componente pertenece cada nodo
    vector<int> componente(n, -1);
    int cantidadComponentes = 0;
 
    for(int i = 0; i < n; i++) {
        // si no encontramos ya la componente del nodo i
        if(componente[i] == -1) {
            // marcamos a todos los nodos de la componente de i con el número cantidadComponentes
            dfs(i, grafo, componente, cantidadComponentes);
            cantidadComponentes++;
        }
    }
 
    // Se puede devolver directamente el vector componente si nos es más cómodo para el problema
    vector<vector<int>> componentes(cantidadComponentes);
    for(int i = 0; i < n; i++) {
        componentes[componente[i]].push_back(i);
    }
    return componentes;
}
algoritmos-oia/grafos/componentes-conexas.1589324078.txt.gz · Última modificación: 2020/05/12 22:54 por ariel