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