Un ciclo ocurre cuando se regresa a un nodo por otro camino y se forma una vuelta completa. Detectar ciclos indica si un grafo puede recorrerse sin repetir aristas y es clave para tareas como ordenamiento topológico o validación de dependencias.
Un ciclo se detecta cuando en DFS encontramos un vecino ya visitado que no es el padre inmediato. Las aristas duplicadas o multigrafos requieren controles adicionales.
Abrir detector de ciclos en grafos no dirigidos
En digrafos, un ciclo se produce si alcanzamos un nodo que está en la pila de recursión (en proceso). El orden de visita importa y las aristas se siguen en su dirección.
Abrir detector de ciclos en grafos dirigidos
El arreglo en_recursion[] marca los nodos actualmente en la llamada recursiva. Si en DFS llegamos a un vecino con en_recursion[v] == 1, hay ciclo dirigido.
v != padre.en_recursion puede ocultar ciclos posteriores.#include <stdio.h>
#include <stdlib.h>
typedef struct Arista {
int destino;
struct Arista *sig;
} Arista;
typedef struct {
int n;
Arista **listas;
} Grafo;
int dfsNoDirigido(const Grafo *g, int u, int padre, int *visitado) {
visitado[u] = 1;
for (Arista *it = g->listas[u]; it; it = it->sig) {
int v = it->destino;
if (!visitado[v]) {
if (dfsNoDirigido(g, v, u, visitado)) return 1;
} else if (v != padre) {
return 1; /* ciclo */
}
}
return 0;
}
int dfsDirigido(const Grafo *g, int u, int *visitado, int *enRecursion) {
visitado[u] = 1;
enRecursion[u] = 1;
for (Arista *it = g->listas[u]; it; it = it->sig) {
int v = it->destino;
if (!visitado[v]) {
if (dfsDirigido(g, v, visitado, enRecursion)) return 1;
} else if (enRecursion[v]) {
return 1; /* back edge */
}
}
enRecursion[u] = 0;
return 0;
}
int hayCicloNoDirigido(const Grafo *g) {
int *visitado = calloc(g->n, sizeof(int));
int ciclo = 0;
for (int u = 0; u < g->n && !ciclo; u++) {
if (!visitado[u]) {
ciclo = dfsNoDirigido(g, u, -1, visitado);
}
}
free(visitado);
return ciclo;
}
int hayCicloDirigido(const Grafo *g) {
int *visitado = calloc(g->n, sizeof(int));
int *enRecursion = calloc(g->n, sizeof(int));
int ciclo = 0;
for (int u = 0; u < g->n && !ciclo; u++) {
if (!visitado[u]) {
ciclo = dfsDirigido(g, u, visitado, enRecursion);
}
}
free(visitado);
free(enRecursion);
return ciclo;
}
El orden topológico es una lista lineal de los vértices de un digrafo acíclico (DAG) donde cada arista u → v respeta el orden: u va antes que v. Sirve para planificar tareas con dependencias o compilar módulos en secuencia. Solo existe si el grafo está libre de ciclos dirigidos.
Se puede obtener con DFS tomando los vértices en orden de finalización inverso, o con el algoritmo de Kahn (cola de nodos con grado de entrada cero). Si durante Kahn te quedas sin nodos y quedan aristas, hay un ciclo y el orden topológico no es posible.