def __satisfies_necessary_and_sufficient_conditions(g):
     """
     Determines whether a digraph has an Eulerian cycle using necessary
     and sufficient conditions (without computing the cycle itself):
        - at least one edge
        - indegree(v) = outdegree(v) for every vertex
        - the graph is connected, when viewed as an undirected graph
          (ignoring isolated vertices)
     """
     # Condition 0: at least 1 Edge
     if g.get_E() == 0:
         return False
     # Condition 1: indegree(v) == outdegree(v) for every vertex
     for v in range(g.get_V()):
         if g.outdegree() != g.indegree(v):
             return False
     # Condition 2: graph is connected, ignoring isolated vertices
     h = Graph(g.get_V())
     for v in range(g.get_V()):
         for w in g.adj_vertices(v):
             h.add_edge(v, w)
     # check that all non-isolated vertices are connected
     s = DirectedEulerianCycle.__non_isolated_vertex(g)
     bfs = BreadthFirstPaths(h, s)
     for v in range(g.get_V()):
         if h.degree(v) > 0 and not bfs.has_path_to(v):
             return False
         return True
 def __satisfies_necessary_and_sufficient_conditions(g):
     """
     Determines whether a digraph has an Eulerian path using necessary
     and sufficient conditions (without computing the path itself):
         - indegree(v) = outdegree(v) for every vertex,
           except one vertex v may have outdegree(v) = indegree(v) + 1
           (and one vertex v may have indegree(v) = outdegree(v) + 1)
         - the graph is connected, when viewed as an undirected graph
           (ignoring isolated vertices)
     """
     # Condition 0: at least 1 Edge
     if g.get_E() == 0:
         return True
     # Condition 1: indegree(v) == outdegree(v) for every vertex,
     # except one vertex may have outdegree(v) = indegree(v) + 1
     deficit = 0
     for v in range(g.get_V()):
         if g.outdegree() > g.indegree(v):
             deficit += (g.outdegree() - g.indegree(v))
     if deficit > 1:
         return False
     # Condition 2: graph is connected, ignoring isolated vertices
     h = Graph(g.get_V())
     for v in range(g.get_V()):
         for w in g.adj_vertices(v):
             h.add_edge(v, w)
     # check that all non-isolated vertices are connected
     s = DirectedEulerianPath.__non_isolated_vertex(g)
     bfs = BreadthFirstPaths(h, s)
     for v in range(g.get_V()):
         if h.degree(v) > 0 and not bfs.has_path_to(v):
             return False
         return True