code: private static <N> boolean subgraphHasCycle(
        Graph<N> graph,
        Map<Object, NodeVisitState> visitedNodes,
        N node,
        @NullableDecl N previousNode) {
      NodeVisitState state = visitedNodes.get(node);
      if (state == NodeVisitState.COMPLETE) {
        return false;
      }
      if (state == NodeVisitState.PENDING) {
        return true;
      }
  
      visitedNodes.put(node, NodeVisitState.PENDING);
      for (N nextNode : graph.successors(node)) {
        if (canTraverseWithoutReusingEdge(graph, nextNode, previousNode)
            && subgraphHasCycle(graph, visitedNodes, nextNode, node)) {
          return true;
        }
      }
      visitedNodes.put(node, NodeVisitState.COMPLETE);
      return false;
    }
docs: Performs a traversal of the nodes reachable from {@code node}. If we ever reach a node we've
  already visited (following only outgoing edges and without reusing edges), we know there's a
  cycle in the graph.