code: def greedy_coloring(adj):
      
  
      # now let's start coloring
      coloring = {}
      colors = {}
      possible_colors = {n: set(range(len(adj))) for n in adj}
      while possible_colors:
  
          # get the n with the fewest possible colors
          n = min(possible_colors, key=lambda n: len(possible_colors[n]))
  
          # assign that node the lowest color it can still have
          color = min(possible_colors[n])
          coloring[n] = color
          if color not in colors:
              colors[color] = {n}
          else:
              colors[color].add(n)
  
          # also remove color from the possible colors for n's neighbors
          for neighbor in adj[n]:
              if neighbor in possible_colors and color in possible_colors[neighbor]:
                  possible_colors[neighbor].remove(color)
  
          # finally remove n from nodes
          del possible_colors[n]
  
      return coloring, colors
docs: Determines a vertex coloring.
  
      Args:
          adj (dict): The edge structure of the graph to be colored.
              `adj` should be of the form {node: neighbors, ...} where
              neighbors is a set.
  
      Returns:
          dict: the coloring {node: color, ...}
          dict: the colors {color: [node, ...], ...}
  
      Note:
          This is a greedy heuristic: the resulting coloring is not
          necessarily minimal.