lemon/euler.h
author kpeter
Tue, 05 Feb 2008 11:24:32 +0000
changeset 2563 5841132a89fd
parent 2445 aaf5787f4d5d
permissions -rw-r--r--
Small fixes in README.
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@2553
     5
 * Copyright (C) 2003-2008
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@2429
    23
/// \ingroup graph_prop
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@2429
    35
  /// \ingroup graph_prop
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;
deba@2405
    65
    typename Graph::template 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
deba@2429
   123
  /// \ingroup graph_prop
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@2445
   152
    typedef typename Graph::UEdge UEdge;
alpar@1818
   153
    typedef typename Graph::EdgeIt EdgeIt;
alpar@1818
   154
    typedef typename Graph::OutEdgeIt OutEdgeIt;
alpar@1818
   155
    typedef typename Graph::InEdgeIt InEdgeIt;
alpar@1818
   156
    
alpar@1818
   157
    const Graph &g;
deba@2405
   158
    typename Graph::template NodeMap<OutEdgeIt> nedge;
deba@2405
   159
    typename Graph::template UEdgeMap<bool> visited;
alpar@1818
   160
    std::list<Edge> euler;
alpar@1818
   161
alpar@1818
   162
  public:
alpar@1818
   163
    
alpar@1818
   164
    ///Constructor
alpar@1818
   165
alpar@1818
   166
    ///\param _g An undirected graph.
alpar@1818
   167
    ///\param start The starting point of the tour. If it is not given
alpar@1818
   168
    ///       the tour will start from the first node.
klao@1909
   169
    UEulerIt(const Graph &_g,typename Graph::Node start=INVALID)
alpar@1818
   170
      : g(_g), nedge(g), visited(g,false)
alpar@1818
   171
    {
alpar@1818
   172
      if(start==INVALID) start=NodeIt(g);
alpar@1818
   173
      for(NodeIt n(g);n!=INVALID;++n) nedge[n]=OutEdgeIt(g,n);
alpar@1818
   174
      while(nedge[start]!=INVALID) {
alpar@1818
   175
	euler.push_back(nedge[start]);
alpar@2445
   176
	visited[nedge[start]]=true;
alpar@1818
   177
	Node next=g.target(nedge[start]);
alpar@1818
   178
	++nedge[start];
alpar@2445
   179
	start=next;
alpar@2445
   180
	while(nedge[start]!=INVALID && visited[nedge[start]]) ++nedge[start];
alpar@1818
   181
      }
alpar@1818
   182
    }
alpar@1818
   183
    
alpar@1818
   184
    ///Edge Conversion
alpar@2445
   185
    operator Edge() const { return euler.empty()?INVALID:euler.front(); }
alpar@2445
   186
    ///Edge Conversion
alpar@2445
   187
    operator UEdge() const { return euler.empty()?INVALID:euler.front(); }
alpar@2445
   188
    ///\e
alpar@2445
   189
    bool operator==(Invalid) const { return euler.empty(); }
alpar@2445
   190
    ///\e
alpar@2445
   191
    bool operator!=(Invalid) const { return !euler.empty(); }
alpar@1818
   192
    
alpar@1818
   193
    ///Next edge of the tour
klao@1909
   194
    UEulerIt &operator++() {
alpar@1818
   195
      Node s=g.target(euler.front());
alpar@1818
   196
      euler.pop_front();
alpar@1818
   197
      typename std::list<Edge>::iterator next=euler.begin();
alpar@1818
   198
alpar@1818
   199
      while(nedge[s]!=INVALID) {
alpar@1818
   200
	while(nedge[s]!=INVALID && visited[nedge[s]]) ++nedge[s];
alpar@1818
   201
	if(nedge[s]==INVALID) break;
alpar@1818
   202
	else {
alpar@1818
   203
	  euler.insert(next,nedge[s]);
alpar@2445
   204
	  visited[nedge[s]]=true;
alpar@1818
   205
	  Node n=g.target(nedge[s]);
alpar@1818
   206
	  ++nedge[s];
alpar@1818
   207
	  s=n;
alpar@1818
   208
	}
alpar@1818
   209
      }
alpar@1818
   210
      return *this;
alpar@1818
   211
    }
alpar@1818
   212
    
alpar@1818
   213
    ///Postfix incrementation
alpar@1818
   214
    
alpar@1818
   215
    ///\warning This incrementation
klao@1909
   216
    ///returns an \c Edge, not an \ref UEulerIt, as one may
alpar@1818
   217
    ///expect.
alpar@1818
   218
    Edge operator++(int) 
alpar@1818
   219
    {
alpar@1818
   220
      Edge e=*this;
alpar@1818
   221
      ++(*this);
alpar@1818
   222
      return e;
alpar@1818
   223
    }
alpar@1818
   224
  };
alpar@1818
   225
alpar@1818
   226
alpar@1738
   227
  ///Checks if the graph is Euler
alpar@1738
   228
deba@2429
   229
  /// \ingroup graph_prop
alpar@1738
   230
  ///Checks if the graph is Euler. It works for both directed and
alpar@1738
   231
  ///undirected graphs.
alpar@1818
   232
  ///\note By definition, a directed graph is called \e Euler if
alpar@1818
   233
  ///and only if connected and the number of it is incoming and outgoing edges
alpar@1818
   234
  ///are the same for each node.
alpar@1818
   235
  ///Similarly, an undirected graph is called \e Euler if
alpar@1818
   236
  ///and only if it is connected and the number of incident edges is even
alpar@1818
   237
  ///for each node. <em>Therefore, there are graphs which are not Euler, but
alpar@1818
   238
  ///still have an Euler tour</em>.
alpar@1738
   239
  ///\todo Test required
alpar@1738
   240
  template<class Graph>
alpar@1738
   241
#ifdef DOXYGEN
alpar@1738
   242
  bool
alpar@1738
   243
#else
deba@1979
   244
  typename enable_if<UndirectedTagIndicator<Graph>,bool>::type
alpar@1818
   245
  euler(const Graph &g) 
alpar@1818
   246
  {
alpar@1818
   247
    for(typename Graph::NodeIt n(g);n!=INVALID;++n)
alpar@1818
   248
      if(countIncEdges(g,n)%2) return false;
alpar@1818
   249
    return connected(g);
alpar@1818
   250
  }
alpar@1818
   251
  template<class Graph>
deba@1979
   252
  typename disable_if<UndirectedTagIndicator<Graph>,bool>::type
alpar@1738
   253
#endif
alpar@1738
   254
  euler(const Graph &g) 
alpar@1738
   255
  {
alpar@1738
   256
    for(typename Graph::NodeIt n(g);n!=INVALID;++n)
alpar@1738
   257
      if(countInEdges(g,n)!=countOutEdges(g,n)) return false;
alpar@1818
   258
    return connected(g);
alpar@1738
   259
  }
alpar@1738
   260
  
alpar@1738
   261
}