Write has_cycle(n, edges) -> bool. The graph is directed, with nodes 0 .. n-1, and each pair (a, b) in edges is an edge from a to b. Return True if some path leaves a node and comes back to it, otherwise False.
has_cycle(4, [(0, 1), (1, 2), (2, 0), (2, 3)]) # True 0 -> 1 -> 2 -> 0
has_cycle(4, [(0, 1), (0, 2), (1, 3), (2, 3)]) # False two routes to 3 is not a cycle
The trap is the second example: a plain "seen" set says you revisited 3, but in a directed graph that isn't a loop. A self-loop (a, a) is a cycle. The graph may be disconnected, so start a search from every node you haven't finished yet.
Constraints: 1 <= n <= 200, up to 1000 edges, so plain recursion is fine.
Show hint
DFS with three colours: white (unvisited), grey (on the current DFS path) and black (fully explored); reaching a grey node means you found a cycle, while reaching a black one is harmless.