lemon/euler.h
author Balazs Dezso <deba@google.com>
Fri, 22 Jan 2021 10:55:32 +0100
changeset 1208 c6aa2cc1af04
parent 919 e0cef67fe565
permissions -rw-r--r--
Factor out recursion from weighted matching algorithms (#638)
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2013
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #ifndef LEMON_EULER_H
    20 #define LEMON_EULER_H
    21 
    22 #include<lemon/core.h>
    23 #include<lemon/adaptors.h>
    24 #include<lemon/connectivity.h>
    25 #include <list>
    26 
    27 /// \ingroup graph_properties
    28 /// \file
    29 /// \brief Euler tour iterators and a function for checking the \e Eulerian
    30 /// property.
    31 ///
    32 ///This file provides Euler tour iterators and a function to check
    33 ///if a (di)graph is \e Eulerian.
    34 
    35 namespace lemon {
    36 
    37   ///Euler tour iterator for digraphs.
    38 
    39   /// \ingroup graph_properties
    40   ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed
    41   ///graph (if there exists) and it converts to the \c Arc type of the digraph.
    42   ///
    43   ///For example, if the given digraph has an Euler tour (i.e it has only one
    44   ///non-trivial component and the in-degree is equal to the out-degree
    45   ///for all nodes), then the following code will put the arcs of \c g
    46   ///to the vector \c et according to an Euler tour of \c g.
    47   ///\code
    48   ///  std::vector<ListDigraph::Arc> et;
    49   ///  for(DiEulerIt<ListDigraph> e(g); e!=INVALID; ++e)
    50   ///    et.push_back(e);
    51   ///\endcode
    52   ///If \c g has no Euler tour, then the resulted walk will not be closed
    53   ///or not contain all arcs.
    54   ///\sa EulerIt
    55   template<typename GR>
    56   class DiEulerIt
    57   {
    58     typedef typename GR::Node Node;
    59     typedef typename GR::NodeIt NodeIt;
    60     typedef typename GR::Arc Arc;
    61     typedef typename GR::ArcIt ArcIt;
    62     typedef typename GR::OutArcIt OutArcIt;
    63     typedef typename GR::InArcIt InArcIt;
    64 
    65     const GR &g;
    66     typename GR::template NodeMap<OutArcIt> narc;
    67     std::list<Arc> euler;
    68 
    69   public:
    70 
    71     ///Constructor
    72 
    73     ///Constructor.
    74     ///\param gr A digraph.
    75     ///\param start The starting point of the tour. If it is not given,
    76     ///the tour will start from the first node that has an outgoing arc.
    77     DiEulerIt(const GR &gr, typename GR::Node start = INVALID)
    78       : g(gr), narc(g)
    79     {
    80       if (start==INVALID) {
    81         NodeIt n(g);
    82         while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
    83         start=n;
    84       }
    85       if (start!=INVALID) {
    86         for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n);
    87         while (narc[start]!=INVALID) {
    88           euler.push_back(narc[start]);
    89           Node next=g.target(narc[start]);
    90           ++narc[start];
    91           start=next;
    92         }
    93       }
    94     }
    95 
    96     ///Arc conversion
    97     operator Arc() { return euler.empty()?INVALID:euler.front(); }
    98     ///Compare with \c INVALID
    99     bool operator==(Invalid) { return euler.empty(); }
   100     ///Compare with \c INVALID
   101     bool operator!=(Invalid) { return !euler.empty(); }
   102 
   103     ///Next arc of the tour
   104 
   105     ///Next arc of the tour
   106     ///
   107     DiEulerIt &operator++() {
   108       Node s=g.target(euler.front());
   109       euler.pop_front();
   110       typename std::list<Arc>::iterator next=euler.begin();
   111       while(narc[s]!=INVALID) {
   112         euler.insert(next,narc[s]);
   113         Node n=g.target(narc[s]);
   114         ++narc[s];
   115         s=n;
   116       }
   117       return *this;
   118     }
   119     ///Postfix incrementation
   120 
   121     /// Postfix incrementation.
   122     ///
   123     ///\warning This incrementation
   124     ///returns an \c Arc, not a \ref DiEulerIt, as one may
   125     ///expect.
   126     Arc operator++(int)
   127     {
   128       Arc e=*this;
   129       ++(*this);
   130       return e;
   131     }
   132   };
   133 
   134   ///Euler tour iterator for graphs.
   135 
   136   /// \ingroup graph_properties
   137   ///This iterator provides an Euler tour (Eulerian circuit) of an
   138   ///\e undirected graph (if there exists) and it converts to the \c Arc
   139   ///and \c Edge types of the graph.
   140   ///
   141   ///For example, if the given graph has an Euler tour (i.e it has only one
   142   ///non-trivial component and the degree of each node is even),
   143   ///the following code will print the arc IDs according to an
   144   ///Euler tour of \c g.
   145   ///\code
   146   ///  for(EulerIt<ListGraph> e(g); e!=INVALID; ++e) {
   147   ///    std::cout << g.id(Edge(e)) << std::eol;
   148   ///  }
   149   ///\endcode
   150   ///Although this iterator is for undirected graphs, it still returns
   151   ///arcs in order to indicate the direction of the tour.
   152   ///(But arcs convert to edges, of course.)
   153   ///
   154   ///If \c g has no Euler tour, then the resulted walk will not be closed
   155   ///or not contain all edges.
   156   template<typename GR>
   157   class EulerIt
   158   {
   159     typedef typename GR::Node Node;
   160     typedef typename GR::NodeIt NodeIt;
   161     typedef typename GR::Arc Arc;
   162     typedef typename GR::Edge Edge;
   163     typedef typename GR::ArcIt ArcIt;
   164     typedef typename GR::OutArcIt OutArcIt;
   165     typedef typename GR::InArcIt InArcIt;
   166 
   167     const GR &g;
   168     typename GR::template NodeMap<OutArcIt> narc;
   169     typename GR::template EdgeMap<bool> visited;
   170     std::list<Arc> euler;
   171 
   172   public:
   173 
   174     ///Constructor
   175 
   176     ///Constructor.
   177     ///\param gr A graph.
   178     ///\param start The starting point of the tour. If it is not given,
   179     ///the tour will start from the first node that has an incident edge.
   180     EulerIt(const GR &gr, typename GR::Node start = INVALID)
   181       : g(gr), narc(g), visited(g, false)
   182     {
   183       if (start==INVALID) {
   184         NodeIt n(g);
   185         while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
   186         start=n;
   187       }
   188       if (start!=INVALID) {
   189         for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n);
   190         while(narc[start]!=INVALID) {
   191           euler.push_back(narc[start]);
   192           visited[narc[start]]=true;
   193           Node next=g.target(narc[start]);
   194           ++narc[start];
   195           start=next;
   196           while(narc[start]!=INVALID && visited[narc[start]]) ++narc[start];
   197         }
   198       }
   199     }
   200 
   201     ///Arc conversion
   202     operator Arc() const { return euler.empty()?INVALID:euler.front(); }
   203     ///Edge conversion
   204     operator Edge() const { return euler.empty()?INVALID:euler.front(); }
   205     ///Compare with \c INVALID
   206     bool operator==(Invalid) const { return euler.empty(); }
   207     ///Compare with \c INVALID
   208     bool operator!=(Invalid) const { return !euler.empty(); }
   209 
   210     ///Next arc of the tour
   211 
   212     ///Next arc of the tour
   213     ///
   214     EulerIt &operator++() {
   215       Node s=g.target(euler.front());
   216       euler.pop_front();
   217       typename std::list<Arc>::iterator next=euler.begin();
   218       while(narc[s]!=INVALID) {
   219         while(narc[s]!=INVALID && visited[narc[s]]) ++narc[s];
   220         if(narc[s]==INVALID) break;
   221         else {
   222           euler.insert(next,narc[s]);
   223           visited[narc[s]]=true;
   224           Node n=g.target(narc[s]);
   225           ++narc[s];
   226           s=n;
   227         }
   228       }
   229       return *this;
   230     }
   231 
   232     ///Postfix incrementation
   233 
   234     /// Postfix incrementation.
   235     ///
   236     ///\warning This incrementation returns an \c Arc (which converts to
   237     ///an \c Edge), not an \ref EulerIt, as one may expect.
   238     Arc operator++(int)
   239     {
   240       Arc e=*this;
   241       ++(*this);
   242       return e;
   243     }
   244   };
   245 
   246 
   247   ///Check if the given graph is Eulerian
   248 
   249   /// \ingroup graph_properties
   250   ///This function checks if the given graph is Eulerian.
   251   ///It works for both directed and undirected graphs.
   252   ///
   253   ///By definition, a digraph is called \e Eulerian if
   254   ///and only if it is connected and the number of incoming and outgoing
   255   ///arcs are the same for each node.
   256   ///Similarly, an undirected graph is called \e Eulerian if
   257   ///and only if it is connected and the number of incident edges is even
   258   ///for each node.
   259   ///
   260   ///\note There are (di)graphs that are not Eulerian, but still have an
   261   /// Euler tour, since they may contain isolated nodes.
   262   ///
   263   ///\sa DiEulerIt, EulerIt
   264   template<typename GR>
   265 #ifdef DOXYGEN
   266   bool
   267 #else
   268   typename enable_if<UndirectedTagIndicator<GR>,bool>::type
   269   eulerian(const GR &g)
   270   {
   271     for(typename GR::NodeIt n(g);n!=INVALID;++n)
   272       if(countIncEdges(g,n)%2) return false;
   273     return connected(g);
   274   }
   275   template<class GR>
   276   typename disable_if<UndirectedTagIndicator<GR>,bool>::type
   277 #endif
   278   eulerian(const GR &g)
   279   {
   280     for(typename GR::NodeIt n(g);n!=INVALID;++n)
   281       if(countInArcs(g,n)!=countOutArcs(g,n)) return false;
   282     return connected(undirector(g));
   283   }
   284 
   285 }
   286 
   287 #endif