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 |
}
|