function has_cycle(graph): # directed graph, via DFS colors
   color = {v: "white" for v in graph}

   function visit(u):
      color[u] = "gray"
      for v in graph[u]:
        if color[v] == "gray": return true # back edge found
        if color[v] == "white" and visit(v): return true

      color[u] = "black"
      return false
   return any(visit(v) for v in graph if color[v] == "white")
