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