Detect Cycle in Undirected Graph (DFS)
Does an undirected graph contain a cycle? Detect it with DFS.
Open on GeeksforGeeks ↗Intuition
Identical rule to the BFS version — an already-visited neighbour that is not the parent closes a loop — but the parent travels down the recursion instead of inside a queue. Such an edge is called a back edge, and in an undirected graph a back edge and a cycle are the same thing.
In an undirected graph every edge is stored twice, so the node you just came from will always look like a revisit. Passing the parent down and excusing exactly that one neighbour is the whole technique — any other already-seen neighbour is a genuine back edge, and therefore a cycle.
Approach
Pass the parent down
dfs(v, parent): mark v, then for each neighbour u either recurse (if unvisited) or check whether u != parent.
Back edge = cycle
A visited, non-parent neighbour is an edge back into the part of the graph already on the path — the definition of a cycle here.
Why directed graphs need more
In a directed graph an edge into a finished vertex is harmless, so the parent trick fails; that variant needs the grey/black recursion-stack check instead.
Solution & live demo
Common pitfalls
Treating any visited neighbour as a cycle
for u in adj[v]:
if seen[u]: return Trueelif u != parent:
return TrueThe edge you arrived on is bidirectional, so the parent is always already visited — this reports a cycle on a two-node graph with a single edge. The parent must be excluded from the back-edge test.
Discarding the recursive result
if not seen[u]:
dfs(u, v)if not seen[u]:
if dfs(u, v): return TrueA cycle found deeper in the recursion never reaches the caller, so the function reports False for graphs that clearly contain one. Recursive answers have to be propagated up.
Checking only the component containing node 0
return dfs(0, -1)
for s in range(n):
if not seen[s] and dfs(s, -1): return TrueThe cycle may live in a component unreachable from node 0. Every unvisited vertex needs to seed its own search, with -1 standing in for "no parent".
Edge cases
Every visited neighbour is the parent — returns false.
u == v is visited and not the parent — correctly a cycle.
Outer loop covers every component.