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