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.
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.
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.