[Lemon-commits] deba: r3352 - in lemon/trunk: lemon test
Lemon SVN
svn at lemon.cs.elte.hu
Tue Oct 30 21:21:11 CET 2007
Author: deba
Date: Tue Oct 30 21:21:10 2007
New Revision: 3352
Modified:
lemon/trunk/lemon/max_matching.h
lemon/trunk/lemon/unionfind.h
lemon/trunk/test/max_matching_test.cc
lemon/trunk/test/unionfind_test.cc
Log:
Redesign interface of MaxMatching and UnionFindEnum
New class ExtendFindEnum
Faster MaxMatching
Modified: lemon/trunk/lemon/max_matching.h
==============================================================================
--- lemon/trunk/lemon/max_matching.h (original)
+++ lemon/trunk/lemon/max_matching.h Tue Oct 30 21:21:10 2007
@@ -30,25 +30,21 @@
namespace lemon {
- /// \ingroup matching
-
- ///Edmonds' alternating forest maximum matching algorithm.
+ ///\ingroup matching
+ ///\brief Edmonds' alternating forest maximum matching algorithm.
+ ///
///This class provides Edmonds' alternating forest matching
///algorithm. The starting matching (if any) can be passed to the
- ///algorithm using read-in functions \ref readNMapNode, \ref
- ///readNMapEdge or \ref readEMapBool depending on the container. The
- ///resulting maximum matching can be attained by write-out functions
- ///\ref writeNMapNode, \ref writeNMapEdge or \ref writeEMapBool
- ///depending on the preferred container.
+ ///algorithm using some of init functions.
///
///The dual side of a matching is a map of the nodes to
- ///MaxMatching::pos_enum, having values D, A and C showing the
- ///Gallai-Edmonds decomposition of the graph. The nodes in D induce
- ///a graph with factor-critical components, the nodes in A form the
- ///barrier, and the nodes in C induce a graph having a perfect
- ///matching. This decomposition can be attained by calling \ref
- ///writePos after running the algorithm.
+ ///MaxMatching::DecompType, having values \c D, \c A and \c C
+ ///showing the Gallai-Edmonds decomposition of the graph. The nodes
+ ///in \c D induce a graph with factor-critical components, the nodes
+ ///in \c A form the barrier, and the nodes in \c C induce a graph
+ ///having a perfect matching. This decomposition can be attained by
+ ///calling \c decomposition() after running the algorithm.
///
///\param Graph The undirected graph type the algorithm runs on.
///
@@ -67,17 +63,21 @@
typedef typename Graph::template NodeMap<int> UFECrossRef;
typedef UnionFindEnum<UFECrossRef> UFE;
+ typedef std::vector<Node> NV;
+
+ typedef typename Graph::template NodeMap<int> EFECrossRef;
+ typedef ExtendFindEnum<EFECrossRef> EFE;
public:
- ///Indicates the Gallai-Edmonds decomposition of the graph.
-
+ ///\brief Indicates the Gallai-Edmonds decomposition of the graph.
+ ///
///Indicates the Gallai-Edmonds decomposition of the graph, which
///shows an upper bound on the size of a maximum matching. The
- ///nodes with pos_enum \c D induce a graph with factor-critical
+ ///nodes with DecompType \c D induce a graph with factor-critical
///components, the nodes in \c A form the canonical barrier, and the
///nodes in \c C induce a graph having a perfect matching.
- enum pos_enum {
+ enum DecompType {
D=0,
A=1,
C=2
@@ -88,45 +88,169 @@
static const int HEUR_density=2;
const Graph& g;
typename Graph::template NodeMap<Node> _mate;
- typename Graph::template NodeMap<pos_enum> position;
+ typename Graph::template NodeMap<DecompType> position;
public:
- MaxMatching(const Graph& _g) : g(_g), _mate(_g,INVALID), position(_g) {}
+ MaxMatching(const Graph& _g)
+ : g(_g), _mate(_g), position(_g) {}
+
+ ///\brief Sets the actual matching to the empty matching.
+ ///
+ ///Sets the actual matching to the empty matching.
+ ///
+ void init() {
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ _mate.set(v,INVALID);
+ position.set(v,C);
+ }
+ }
+
+ ///\brief Finds a greedy matching for initial matching.
+ ///
+ ///For initial matchig it finds a maximal greedy matching.
+ void greedyInit() {
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ _mate.set(v,INVALID);
+ position.set(v,C);
+ }
+ for(NodeIt v(g); v!=INVALID; ++v)
+ if ( _mate[v]==INVALID ) {
+ for( IncEdgeIt e(g,v); e!=INVALID ; ++e ) {
+ Node y=g.runningNode(e);
+ if ( _mate[y]==INVALID && y!=v ) {
+ _mate.set(v,y);
+ _mate.set(y,v);
+ break;
+ }
+ }
+ }
+ }
+
+ ///\brief Initialize the matching from each nodes' mate.
+ ///
+ ///Initialize the matching from a \c Node valued \c Node map. This
+ ///map must be \e symmetric, i.e. if \c map[u]==v then \c
+ ///map[v]==u must hold, and \c uv will be an edge of the initial
+ ///matching.
+ template <typename MateMap>
+ void mateMapInit(MateMap& map) {
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ _mate.set(v,map[v]);
+ position.set(v,C);
+ }
+ }
+
+ ///\brief Initialize the matching from a node map with the
+ ///incident matching edges.
+ ///
+ ///Initialize the matching from an \c UEdge valued \c Node map. \c
+ ///map[v] must be an \c UEdge incident to \c v. This map must have
+ ///the property that if \c g.oppositeNode(u,map[u])==v then \c \c
+ ///g.oppositeNode(v,map[v])==u holds, and now some edge joining \c
+ ///u to \c v will be an edge of the matching.
+ template<typename MatchingMap>
+ void matchingMapInit(MatchingMap& map) {
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ position.set(v,C);
+ UEdge e=map[v];
+ if ( e!=INVALID )
+ _mate.set(v,g.oppositeNode(v,e));
+ else
+ _mate.set(v,INVALID);
+ }
+ }
+
+ ///\brief Initialize the matching from the map containing the
+ ///undirected matching edges.
+ ///
+ ///Initialize the matching from a \c bool valued \c UEdge map. This
+ ///map must have the property that there are no two incident edges
+ ///\c e, \c f with \c map[e]==map[f]==true. The edges \c e with \c
+ ///map[e]==true form the matching.
+ template <typename MatchingMap>
+ void matchingInit(MatchingMap& map) {
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ _mate.set(v,INVALID);
+ position.set(v,C);
+ }
+ for(UEdgeIt e(g); e!=INVALID; ++e) {
+ if ( map[e] ) {
+ Node u=g.source(e);
+ Node v=g.target(e);
+ _mate.set(u,v);
+ _mate.set(v,u);
+ }
+ }
+ }
- ///Runs Edmonds' algorithm.
+ ///\brief Runs Edmonds' algorithm.
+ ///
///Runs Edmonds' algorithm for sparse graphs (number of edges <
///2*number of nodes), and a heuristical Edmonds' algorithm with a
///heuristic of postponing shrinks for dense graphs.
void run() {
- if ( countUEdges(g) < HEUR_density*countNodes(g) ) {
- greedyMatching();
- runEdmonds(0);
- } else runEdmonds(1);
+ if (countUEdges(g) < HEUR_density * countNodes(g)) {
+ greedyInit();
+ startSparse();
+ } else {
+ init();
+ startDense();
+ }
}
- ///Runs Edmonds' algorithm.
-
- ///If heur=0 it runs Edmonds' algorithm. If heur=1 it runs
- ///Edmonds' algorithm with a heuristic of postponing shrinks,
- ///giving a faster algorithm for dense graphs.
- void runEdmonds( int heur = 1 ) {
+ ///\brief Starts Edmonds' algorithm.
+ ///
+ ///If runs the original Edmonds' algorithm.
+ void startSparse() {
+
+ typename Graph::template NodeMap<Node> ear(g,INVALID);
+ //undefined for the base nodes of the blossoms (i.e. for the
+ //representative elements of UFE blossom) and for the nodes in C
- //each vertex is put to C
- for(NodeIt v(g); v!=INVALID; ++v)
- position.set(v,C);
+ UFECrossRef blossom_base(g);
+ UFE blossom(blossom_base);
+ NV rep(countNodes(g));
+
+ EFECrossRef tree_base(g);
+ EFE tree(tree_base);
+
+ //If these UFE's would be members of the class then also
+ //blossom_base and tree_base should be a member.
+ //We build only one tree and the other vertices uncovered by the
+ //matching belong to C. (They can be considered as singleton
+ //trees.) If this tree can be augmented or no more
+ //grow/augmentation/shrink is possible then we return to this
+ //"for" cycle.
+ for(NodeIt v(g); v!=INVALID; ++v) {
+ if (position[v]==C && _mate[v]==INVALID) {
+ rep[blossom.insert(v)] = v;
+ tree.insert(v);
+ position.set(v,D);
+ normShrink(v, ear, blossom, rep, tree);
+ }
+ }
+ }
+
+ ///\brief Starts Edmonds' algorithm.
+ ///
+ ///It runs Edmonds' algorithm with a heuristic of postponing
+ ///shrinks, giving a faster algorithm for dense graphs.
+ void startDense() {
+
typename Graph::template NodeMap<Node> ear(g,INVALID);
//undefined for the base nodes of the blossoms (i.e. for the
//representative elements of UFE blossom) and for the nodes in C
UFECrossRef blossom_base(g);
UFE blossom(blossom_base);
+ NV rep(countNodes(g));
- UFECrossRef tree_base(g);
- UFE tree(tree_base);
+ EFECrossRef tree_base(g);
+ EFE tree(tree_base);
//If these UFE's would be members of the class then also
//blossom_base and tree_base should be a member.
@@ -138,36 +262,18 @@
//"for" cycle.
for(NodeIt v(g); v!=INVALID; ++v) {
if ( position[v]==C && _mate[v]==INVALID ) {
- blossom.insert(v);
+ rep[blossom.insert(v)] = v;
tree.insert(v);
position.set(v,D);
- if ( heur == 1 ) lateShrink( v, ear, blossom, tree );
- else normShrink( v, ear, blossom, tree );
+ lateShrink(v, ear, blossom, rep, tree);
}
}
}
- ///Finds a greedy matching starting from the actual matching.
-
- ///Starting form the actual matching stored, it finds a maximal
- ///greedy matching.
- void greedyMatching() {
- for(NodeIt v(g); v!=INVALID; ++v)
- if ( _mate[v]==INVALID ) {
- for( IncEdgeIt e(g,v); e!=INVALID ; ++e ) {
- Node y=g.runningNode(e);
- if ( _mate[y]==INVALID && y!=v ) {
- _mate.set(v,y);
- _mate.set(y,v);
- break;
- }
- }
- }
- }
-
- ///Returns the size of the actual matching stored.
+ ///\brief Returns the size of the actual matching stored.
+ ///
///Returns the size of the actual matching stored. After \ref
///run() it returns the size of a maximum matching in the graph.
int size() const {
@@ -181,75 +287,70 @@
}
- ///Resets the actual matching to the empty matching.
-
- ///Resets the actual matching to the empty matching.
+ ///\brief Returns the mate of a node in the actual matching.
///
- void resetMatching() {
- for(NodeIt v(g); v!=INVALID; ++v)
- _mate.set(v,INVALID);
- }
-
- ///Returns the mate of a node in the actual matching.
-
///Returns the mate of a \c node in the actual matching.
///Returns INVALID if the \c node is not covered by the actual matching.
- Node mate(Node& node) const {
+ Node mate(const Node& node) const {
return _mate[node];
}
- ///Reads a matching from a \c Node valued \c Node map.
-
- ///Reads a matching from a \c Node valued \c Node map. This map
- ///must be \e symmetric, i.e. if \c map[u]==v then \c map[v]==u
- ///must hold, and \c uv will be an edge of the matching.
- template<typename NMapN>
- void readNMapNode(NMapN& map) {
- for(NodeIt v(g); v!=INVALID; ++v) {
- _mate.set(v,map[v]);
- }
+ ///\brief Returns the matching edge incident to the given node.
+ ///
+ ///Returns the matching edge of a \c node in the actual matching.
+ ///Returns INVALID if the \c node is not covered by the actual matching.
+ UEdge matchingEdge(const Node& node) const {
+ if (_mate[node] == INVALID) return INVALID;
+ Node n = node < _mate[node] ? node : _mate[node];
+ for (IncEdgeIt e(g, n); e != INVALID; ++e) {
+ if (g.oppositeNode(n, e) == _mate[n]) {
+ return e;
+ }
+ }
+ return INVALID;
}
-
- ///Writes the stored matching to a \c Node valued \c Node map.
+ /// \brief Returns the class of the node in the Edmonds-Gallai
+ /// decomposition.
+ ///
+ /// Returns the class of the node in the Edmonds-Gallai
+ /// decomposition.
+ DecompType decomposition(const Node& n) {
+ return position[n] == A;
+ }
+
+ /// \brief Returns true when the node is in the barrier.
+ ///
+ /// Returns true when the node is in the barrier.
+ bool barrier(const Node& n) {
+ return position[n] == A;
+ }
+
+ ///\brief Gives back the matching in a \c Node of mates.
+ ///
///Writes the stored matching to a \c Node valued \c Node map. The
///resulting map will be \e symmetric, i.e. if \c map[u]==v then \c
///map[v]==u will hold, and now \c uv is an edge of the matching.
- template<typename NMapN>
- void writeNMapNode (NMapN& map) const {
+ template <typename MateMap>
+ void mateMap(MateMap& map) const {
for(NodeIt v(g); v!=INVALID; ++v) {
map.set(v,_mate[v]);
}
}
-
- ///Reads a matching from an \c UEdge valued \c Node map.
-
- ///Reads a matching from an \c UEdge valued \c Node map. \c
- ///map[v] must be an \c UEdge incident to \c v. This map must
- ///have the property that if \c g.oppositeNode(u,map[u])==v then
- ///\c \c g.oppositeNode(v,map[v])==u holds, and now some edge
- ///joining \c u to \c v will be an edge of the matching.
- template<typename NMapE>
- void readNMapEdge(NMapE& map) {
- for(NodeIt v(g); v!=INVALID; ++v) {
- UEdge e=map[v];
- if ( e!=INVALID )
- _mate.set(v,g.oppositeNode(v,e));
- }
- }
- ///Writes the matching stored to an \c UEdge valued \c Node map.
-
+ ///\brief Gives back the matching in an \c UEdge valued \c Node
+ ///map.
+ ///
///Writes the stored matching to an \c UEdge valued \c Node
///map. \c map[v] will be an \c UEdge incident to \c v. This
///map will have the property that if \c g.oppositeNode(u,map[u])
///== v then \c map[u]==map[v] holds, and now this edge is an edge
///of the matching.
- template<typename NMapE>
- void writeNMapEdge (NMapE& map) const {
+ template <typename MatchingMap>
+ void matchingMap(MatchingMap& map) const {
typename Graph::template NodeMap<bool> todo(g,true);
for(NodeIt v(g); v!=INVALID; ++v) {
- if ( todo[v] && _mate[v]!=INVALID ) {
+ if (_mate[v]!=INVALID && v < _mate[v]) {
Node u=_mate[v];
for(IncEdgeIt e(g,v); e!=INVALID; ++e) {
if ( g.runningNode(e) == u ) {
@@ -265,33 +366,15 @@
}
- ///Reads a matching from a \c bool valued \c Edge map.
-
- ///Reads a matching from a \c bool valued \c Edge map. This map
- ///must have the property that there are no two incident edges \c
- ///e, \c f with \c map[e]==map[f]==true. The edges \c e with \c
- ///map[e]==true form the matching.
- template<typename EMapB>
- void readEMapBool(EMapB& map) {
- for(UEdgeIt e(g); e!=INVALID; ++e) {
- if ( map[e] ) {
- Node u=g.source(e);
- Node v=g.target(e);
- _mate.set(u,v);
- _mate.set(v,u);
- }
- }
- }
-
-
- ///Writes the matching stored to a \c bool valued \c Edge map.
-
+ ///\brief Gives back the matching in a \c bool valued \c UEdge
+ ///map.
+ ///
///Writes the matching stored to a \c bool valued \c Edge
///map. This map will have the property that there are no two
///incident edges \c e, \c f with \c map[e]==map[f]==true. The
///edges \c e with \c map[e]==true form the matching.
- template<typename EMapB>
- void writeEMapBool (EMapB& map) const {
+ template<typename MatchingMap>
+ void matching(MatchingMap& map) const {
for(UEdgeIt e(g); e!=INVALID; ++e) map.set(e,false);
typename Graph::template NodeMap<bool> todo(g,true);
@@ -311,262 +394,230 @@
}
- ///Writes the canonical decomposition of the graph after running
+ ///\brief Returns the canonical decomposition of the graph after running
///the algorithm.
-
+ ///
///After calling any run methods of the class, it writes the
///Gallai-Edmonds canonical decomposition of the graph. \c map
- ///must be a node map of \ref pos_enum 's.
- template<typename NMapEnum>
- void writePos (NMapEnum& map) const {
- for(NodeIt v(g); v!=INVALID; ++v) map.set(v,position[v]);
+ ///must be a node map of \ref DecompType 's.
+ template <typename DecompositionMap>
+ void decomposition(DecompositionMap& map) const {
+ for(NodeIt v(g); v!=INVALID; ++v) map.set(v,position[v]);
+ }
+
+ ///\brief Returns a barrier on the nodes.
+ ///
+ ///After calling any run methods of the class, it writes a
+ ///canonical barrier on the nodes. The odd component number of the
+ ///remaining graph minus the barrier size is a lower bound for the
+ ///uncovered nodes in the graph. The \c map must be a node map of
+ ///bools.
+ template <typename BarrierMap>
+ void barrier(BarrierMap& barrier) {
+ for(NodeIt v(g); v!=INVALID; ++v) barrier.set(v,position[v] == A);
}
private:
void lateShrink(Node v, typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree);
-
- void normShrink(Node v, typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree);
-
- void shrink(Node x,Node y, typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree,std::queue<Node>& Q);
-
- void shrinkStep(Node& top, Node& middle, Node& bottom,
- typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree, std::queue<Node>& Q);
-
- bool growOrAugment(Node& y, Node& x, typename Graph::template
- NodeMap<Node>& ear, UFE& blossom, UFE& tree,
- std::queue<Node>& Q);
-
- void augment(Node x, typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree);
-
- };
-
-
- // **********************************************************************
- // IMPLEMENTATIONS
- // **********************************************************************
-
-
- template <typename Graph>
- void MaxMatching<Graph>::lateShrink(Node v, typename Graph::template
- NodeMap<Node>& ear, UFE& blossom,
- UFE& tree) {
- //We have one tree which we grow, and also shrink but only if it cannot be
- //postponed. If we augment then we return to the "for" cycle of
- //runEdmonds().
-
- std::queue<Node> Q; //queue of the totally unscanned nodes
- Q.push(v);
- std::queue<Node> R;
- //queue of the nodes which must be scanned for a possible shrink
+ UFE& blossom, NV& rep, EFE& tree) {
+ //We have one tree which we grow, and also shrink but only if it
+ //cannot be postponed. If we augment then we return to the "for"
+ //cycle of runEdmonds().
+
+ std::queue<Node> Q; //queue of the totally unscanned nodes
+ Q.push(v);
+ std::queue<Node> R;
+ //queue of the nodes which must be scanned for a possible shrink
- while ( !Q.empty() ) {
- Node x=Q.front();
- Q.pop();
- for( IncEdgeIt e(g,x); e!= INVALID; ++e ) {
- Node y=g.runningNode(e);
- //growOrAugment grows if y is covered by the matching and
- //augments if not. In this latter case it returns 1.
- if ( position[y]==C && growOrAugment(y, x, ear, blossom, tree, Q) )
- return;
+ while ( !Q.empty() ) {
+ Node x=Q.front();
+ Q.pop();
+ for( IncEdgeIt e(g,x); e!= INVALID; ++e ) {
+ Node y=g.runningNode(e);
+ //growOrAugment grows if y is covered by the matching and
+ //augments if not. In this latter case it returns 1.
+ if (position[y]==C &&
+ growOrAugment(y, x, ear, blossom, rep, tree, Q)) return;
+ }
+ R.push(x);
}
- R.push(x);
- }
- while ( !R.empty() ) {
- Node x=R.front();
- R.pop();
+ while ( !R.empty() ) {
+ Node x=R.front();
+ R.pop();
- for( IncEdgeIt e(g,x); e!=INVALID ; ++e ) {
- Node y=g.runningNode(e);
+ for( IncEdgeIt e(g,x); e!=INVALID ; ++e ) {
+ Node y=g.runningNode(e);
- if ( position[y] == D && blossom.find(x) != blossom.find(y) )
- //Recall that we have only one tree.
- shrink( x, y, ear, blossom, tree, Q);
+ if ( position[y] == D && blossom.find(x) != blossom.find(y) )
+ //Recall that we have only one tree.
+ shrink( x, y, ear, blossom, rep, tree, Q);
- while ( !Q.empty() ) {
- Node z=Q.front();
- Q.pop();
- for( IncEdgeIt f(g,z); f!= INVALID; ++f ) {
- Node w=g.runningNode(f);
- //growOrAugment grows if y is covered by the matching and
- //augments if not. In this latter case it returns 1.
- if ( position[w]==C && growOrAugment(w, z, ear, blossom, tree, Q) )
- return;
+ while ( !Q.empty() ) {
+ Node z=Q.front();
+ Q.pop();
+ for( IncEdgeIt f(g,z); f!= INVALID; ++f ) {
+ Node w=g.runningNode(f);
+ //growOrAugment grows if y is covered by the matching and
+ //augments if not. In this latter case it returns 1.
+ if (position[w]==C &&
+ growOrAugment(w, z, ear, blossom, rep, tree, Q)) return;
+ }
+ R.push(z);
}
- R.push(z);
- }
- } //for e
- } // while ( !R.empty() )
- }
-
+ } //for e
+ } // while ( !R.empty() )
+ }
- template <typename Graph>
- void MaxMatching<Graph>::normShrink(Node v,
- typename Graph::template
- NodeMap<Node>& ear,
- UFE& blossom, UFE& tree) {
- //We have one tree, which we grow and shrink. If we augment then we
- //return to the "for" cycle of runEdmonds().
-
- std::queue<Node> Q; //queue of the unscanned nodes
- Q.push(v);
- while ( !Q.empty() ) {
+ void normShrink(Node v, typename Graph::template NodeMap<Node>& ear,
+ UFE& blossom, NV& rep, EFE& tree) {
+ //We have one tree, which we grow and shrink. If we augment then we
+ //return to the "for" cycle of runEdmonds().
+
+ std::queue<Node> Q; //queue of the unscanned nodes
+ Q.push(v);
+ while ( !Q.empty() ) {
- Node x=Q.front();
- Q.pop();
+ Node x=Q.front();
+ Q.pop();
- for( IncEdgeIt e(g,x); e!=INVALID; ++e ) {
- Node y=g.runningNode(e);
+ for( IncEdgeIt e(g,x); e!=INVALID; ++e ) {
+ Node y=g.runningNode(e);
- switch ( position[y] ) {
- case D: //x and y must be in the same tree
- if ( blossom.find(x) != blossom.find(y) )
- //x and y are in the same tree
- shrink( x, y, ear, blossom, tree, Q);
- break;
- case C:
- //growOrAugment grows if y is covered by the matching and
- //augments if not. In this latter case it returns 1.
- if ( growOrAugment(y, x, ear, blossom, tree, Q) ) return;
- break;
- default: break;
- }
+ switch ( position[y] ) {
+ case D: //x and y must be in the same tree
+ if ( blossom.find(x) != blossom.find(y))
+ //x and y are in the same tree
+ shrink(x, y, ear, blossom, rep, tree, Q);
+ break;
+ case C:
+ //growOrAugment grows if y is covered by the matching and
+ //augments if not. In this latter case it returns 1.
+ if (growOrAugment(y, x, ear, blossom, rep, tree, Q)) return;
+ break;
+ default: break;
+ }
+ }
}
}
- }
-
- template <typename Graph>
- void MaxMatching<Graph>::shrink(Node x,Node y, typename
- Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree, std::queue<Node>& Q) {
- //x and y are the two adjacent vertices in two blossoms.
+ void shrink(Node x,Node y, typename Graph::template NodeMap<Node>& ear,
+ UFE& blossom, NV& rep, EFE& tree,std::queue<Node>& Q) {
+ //x and y are the two adjacent vertices in two blossoms.
- typename Graph::template NodeMap<bool> path(g,false);
+ typename Graph::template NodeMap<bool> path(g,false);
- Node b=blossom.find(x);
- path.set(b,true);
- b=_mate[b];
- while ( b!=INVALID ) {
- b=blossom.find(ear[b]);
+ Node b=rep[blossom.find(x)];
path.set(b,true);
b=_mate[b];
- } //we go until the root through bases of blossoms and odd vertices
-
- Node top=y;
- Node middle=blossom.find(top);
- Node bottom=x;
- while ( !path[middle] )
- shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
- //Until we arrive to a node on the path, we update blossom, tree
- //and the positions of the odd nodes.
-
- Node base=middle;
- top=x;
- middle=blossom.find(top);
- bottom=y;
- Node blossom_base=blossom.find(base);
- while ( middle!=blossom_base )
- shrinkStep(top, middle, bottom, ear, blossom, tree, Q);
- //Until we arrive to a node on the path, we update blossom, tree
- //and the positions of the odd nodes.
+ while ( b!=INVALID ) {
+ b=rep[blossom.find(ear[b])];
+ path.set(b,true);
+ b=_mate[b];
+ } //we go until the root through bases of blossoms and odd vertices
+
+ Node top=y;
+ Node middle=rep[blossom.find(top)];
+ Node bottom=x;
+ while ( !path[middle] )
+ shrinkStep(top, middle, bottom, ear, blossom, rep, tree, Q);
+ //Until we arrive to a node on the path, we update blossom, tree
+ //and the positions of the odd nodes.
+
+ Node base=middle;
+ top=x;
+ middle=rep[blossom.find(top)];
+ bottom=y;
+ Node blossom_base=rep[blossom.find(base)];
+ while ( middle!=blossom_base )
+ shrinkStep(top, middle, bottom, ear, blossom, rep, tree, Q);
+ //Until we arrive to a node on the path, we update blossom, tree
+ //and the positions of the odd nodes.
- blossom.makeRep(base);
- }
-
+ rep[blossom.find(base)] = base;
+ }
+ void shrinkStep(Node& top, Node& middle, Node& bottom,
+ typename Graph::template NodeMap<Node>& ear,
+ UFE& blossom, NV& rep, EFE& tree, std::queue<Node>& Q) {
+ //We traverse a blossom and update everything.
+
+ ear.set(top,bottom);
+ Node t=top;
+ while ( t!=middle ) {
+ Node u=_mate[t];
+ t=ear[u];
+ ear.set(t,u);
+ }
+ bottom=_mate[middle];
+ position.set(bottom,D);
+ Q.push(bottom);
+ top=ear[bottom];
+ Node oldmiddle=middle;
+ middle=rep[blossom.find(top)];
+ tree.erase(bottom);
+ tree.erase(oldmiddle);
+ blossom.insert(bottom);
+ blossom.join(bottom, oldmiddle);
+ blossom.join(top, oldmiddle);
+ }
- template <typename Graph>
- void MaxMatching<Graph>::shrinkStep(Node& top, Node& middle, Node& bottom,
- typename Graph::template
- NodeMap<Node>& ear,
- UFE& blossom, UFE& tree,
- std::queue<Node>& Q) {
- //We traverse a blossom and update everything.
-
- ear.set(top,bottom);
- Node t=top;
- while ( t!=middle ) {
- Node u=_mate[t];
- t=ear[u];
- ear.set(t,u);
- }
- bottom=_mate[middle];
- position.set(bottom,D);
- Q.push(bottom);
- top=ear[bottom];
- Node oldmiddle=middle;
- middle=blossom.find(top);
- tree.erase(bottom);
- tree.erase(oldmiddle);
- blossom.insert(bottom);
- blossom.join(bottom, oldmiddle);
- blossom.join(top, oldmiddle);
- }
- template <typename Graph>
- bool MaxMatching<Graph>::growOrAugment(Node& y, Node& x, typename Graph::template
- NodeMap<Node>& ear, UFE& blossom, UFE& tree,
- std::queue<Node>& Q) {
- //x is in a blossom in the tree, y is outside. If y is covered by
- //the matching we grow, otherwise we augment. In this case we
- //return 1.
-
- if ( _mate[y]!=INVALID ) { //grow
- ear.set(y,x);
- Node w=_mate[y];
- blossom.insert(w);
- position.set(y,A);
- position.set(w,D);
- tree.insert(y);
- tree.insert(w);
- tree.join(y,blossom.find(x));
- tree.join(w,y);
- Q.push(w);
- } else { //augment
- augment(x, ear, blossom, tree);
- _mate.set(x,y);
- _mate.set(y,x);
- return true;
+ bool growOrAugment(Node& y, Node& x, typename Graph::template
+ NodeMap<Node>& ear, UFE& blossom, NV& rep, EFE& tree,
+ std::queue<Node>& Q) {
+ //x is in a blossom in the tree, y is outside. If y is covered by
+ //the matching we grow, otherwise we augment. In this case we
+ //return 1.
+
+ if ( _mate[y]!=INVALID ) { //grow
+ ear.set(y,x);
+ Node w=_mate[y];
+ rep[blossom.insert(w)] = w;
+ position.set(y,A);
+ position.set(w,D);
+ int t = tree.find(rep[blossom.find(x)]);
+ tree.insert(y,t);
+ tree.insert(w,t);
+ Q.push(w);
+ } else { //augment
+ augment(x, ear, blossom, rep, tree);
+ _mate.set(x,y);
+ _mate.set(y,x);
+ return true;
+ }
+ return false;
}
- return false;
- }
-
- template <typename Graph>
- void MaxMatching<Graph>::augment(Node x,
- typename Graph::template NodeMap<Node>& ear,
- UFE& blossom, UFE& tree) {
- Node v=_mate[x];
- while ( v!=INVALID ) {
+ void augment(Node x, typename Graph::template NodeMap<Node>& ear,
+ UFE& blossom, NV& rep, EFE& tree) {
+ Node v=_mate[x];
+ while ( v!=INVALID ) {
- Node u=ear[v];
- _mate.set(v,u);
- Node tmp=v;
- v=_mate[u];
- _mate.set(u,tmp);
- }
- Node y=blossom.find(x);
- for (typename UFE::ItemIt tit(tree, y); tit != INVALID; ++tit) {
- if ( position[tit] == D ) {
- for (typename UFE::ItemIt bit(blossom, tit); bit != INVALID; ++bit) {
- position.set( bit ,C);
- }
- blossom.eraseClass(tit);
- } else position.set( tit ,C);
- }
- tree.eraseClass(y);
+ Node u=ear[v];
+ _mate.set(v,u);
+ Node tmp=v;
+ v=_mate[u];
+ _mate.set(u,tmp);
+ }
+ int y = tree.find(rep[blossom.find(x)]);
+ for (typename EFE::ItemIt tit(tree, y); tit != INVALID; ++tit) {
+ if ( position[tit] == D ) {
+ int b = blossom.find(tit);
+ for (typename UFE::ItemIt bit(blossom, b); bit != INVALID; ++bit) {
+ position.set(bit, C);
+ }
+ blossom.eraseClass(b);
+ } else position.set(tit, C);
+ }
+ tree.eraseClass(y);
- }
+ }
+ };
} //END OF NAMESPACE LEMON
Modified: lemon/trunk/lemon/unionfind.h
==============================================================================
--- lemon/trunk/lemon/unionfind.h (original)
+++ lemon/trunk/lemon/unionfind.h Tue Oct 30 21:21:10 2007
@@ -178,26 +178,56 @@
private:
+ ItemIntMap& index;
+
// If the parent stores negative value for an item then that item
- // is root item and it has -items[it].parent component size. Else
+ // is root item and it has ~(items[it].parent) component id. Else
// the items[it].parent contains the index of the parent.
//
- // The \c nextItem and \c prevItem provides the double-linked
- // cyclic list of one component's items. The \c prevClass and
- // \c nextClass gives the double linked list of the representant
- // items.
+ // The \c next and \c prev provides the double-linked
+ // cyclic list of one component's items.
struct ItemT {
int parent;
Item item;
- int nextItem, prevItem;
- int nextClass, prevClass;
+ int next, prev;
};
std::vector<ItemT> items;
- ItemIntMap& index;
+ int firstFreeItem;
+
+ struct ClassT {
+ int size;
+ int firstItem;
+ int next, prev;
+ };
+
+ std::vector<ClassT> classes;
+ int firstClass, firstFreeClass;
+
+ int newClass() {
+ if (firstFreeClass == -1) {
+ int cdx = classes.size();
+ classes.push_back(ClassT());
+ return cdx;
+ } else {
+ int cdx = firstFreeClass;
+ firstFreeClass = classes[firstFreeClass].next;
+ return cdx;
+ }
+ }
- int firstClass;
+ int newItem() {
+ if (firstFreeItem == -1) {
+ int idx = items.size();
+ items.push_back(ItemT());
+ return idx;
+ } else {
+ int idx = firstFreeItem;
+ firstFreeItem = items[firstFreeItem].next;
+ return idx;
+ }
+ }
bool rep(int idx) const {
@@ -217,79 +247,110 @@
return k;
}
- void unlaceClass(int k) {
- if (items[k].prevClass != -1) {
- items[items[k].prevClass].nextClass = items[k].nextClass;
- } else {
- firstClass = items[k].nextClass;
- }
- if (items[k].nextClass != -1) {
- items[items[k].nextClass].prevClass = items[k].prevClass;
- }
- }
+ int classIndex(int idx) const {
+ return ~(items[repIndex(idx)].parent);
+ }
+
+ void singletonItem(int idx) {
+ items[idx].next = idx;
+ items[idx].prev = idx;
+ }
+
+ void laceItem(int idx, int rdx) {
+ items[idx].prev = rdx;
+ items[idx].next = items[rdx].next;
+ items[items[rdx].next].prev = idx;
+ items[rdx].next = idx;
+ }
+
+ void unlaceItem(int idx) {
+ items[items[idx].prev].next = items[idx].next;
+ items[items[idx].next].prev = items[idx].prev;
+
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+ }
void spliceItems(int ak, int bk) {
- items[items[ak].prevItem].nextItem = bk;
- items[items[bk].prevItem].nextItem = ak;
- int tmp = items[ak].prevItem;
- items[ak].prevItem = items[bk].prevItem;
- items[bk].prevItem = tmp;
+ items[items[ak].prev].next = bk;
+ items[items[bk].prev].next = ak;
+ int tmp = items[ak].prev;
+ items[ak].prev = items[bk].prev;
+ items[bk].prev = tmp;
}
+ void laceClass(int cls) {
+ if (firstClass != -1) {
+ classes[firstClass].prev = cls;
+ }
+ classes[cls].next = firstClass;
+ classes[cls].prev = -1;
+ firstClass = cls;
+ }
+
+ void unlaceClass(int cls) {
+ if (classes[cls].prev != -1) {
+ classes[classes[cls].prev].next = classes[cls].next;
+ } else {
+ firstClass = classes[cls].next;
+ }
+ if (classes[cls].next != -1) {
+ classes[classes[cls].next].prev = classes[cls].prev;
+ }
+
+ classes[cls].next = firstFreeClass;
+ firstFreeClass = cls;
+ }
+
public:
UnionFindEnum(ItemIntMap& _index)
- : items(), index(_index), firstClass(-1) {}
+ : index(_index), items(), firstFreeItem(-1),
+ firstClass(-1), firstFreeClass(-1) {}
/// \brief Inserts the given element into a new component.
///
/// This method creates a new component consisting only of the
/// given element.
///
- void insert(const Item& item) {
- ItemT t;
+ int insert(const Item& item) {
+ int idx = newItem();
- int idx = items.size();
index.set(item, idx);
- t.nextItem = idx;
- t.prevItem = idx;
- t.item = item;
- t.parent = -1;
-
- t.nextClass = firstClass;
- if (firstClass != -1) {
- items[firstClass].prevClass = idx;
- }
- t.prevClass = -1;
- firstClass = idx;
+ singletonItem(idx);
+ items[idx].item = item;
+
+ int cdx = newClass();
+
+ items[idx].parent = ~cdx;
- items.push_back(t);
+ laceClass(cdx);
+ classes[cdx].size = 1;
+ classes[cdx].firstItem = idx;
+
+ firstClass = cdx;
+
+ return cdx;
}
/// \brief Inserts the given element into the component of the others.
///
/// This methods inserts the element \e a into the component of the
/// element \e comp.
- void insert(const Item& item, const Item& comp) {
- int k = repIndex(index[comp]);
- ItemT t;
+ void insert(const Item& item, int cls) {
+ int rdx = classes[cls].firstItem;
+ int idx = newItem();
- int idx = items.size();
index.set(item, idx);
- t.prevItem = k;
- t.nextItem = items[k].nextItem;
- items[items[k].nextItem].prevItem = idx;
- items[k].nextItem = idx;
+ laceItem(idx, rdx);
- t.item = item;
- t.parent = k;
+ items[idx].item = item;
+ items[idx].parent = rdx;
- --items[k].parent;
-
- items.push_back(t);
+ ++classes[~(items[rdx].parent)].size;
}
/// \brief Clears the union-find data structure
@@ -298,13 +359,14 @@
void clear() {
items.clear();
firstClass = -1;
+ firstFreeItem = -1;
}
- /// \brief Finds the leader of the component of the given element.
+ /// \brief Finds the component of the given element.
///
- /// The method returns the leader of the component of the given element.
- const Item& find(const Item &item) const {
- return items[repIndex(index[item])].item;
+ /// The method returns the component id of the given element.
+ int find(const Item &item) const {
+ return ~(items[repIndex(index[item])].parent);
}
/// \brief Joining the component of element \e a and element \e b.
@@ -312,90 +374,71 @@
/// This is the \e union operation of the Union-Find structure.
/// Joins the component of element \e a and component of
/// element \e b. If \e a and \e b are in the same component then
- /// returns false else returns true.
- bool join(const Item& a, const Item& b) {
+ /// returns -1 else returns the remaining class.
+ int join(const Item& a, const Item& b) {
int ak = repIndex(index[a]);
int bk = repIndex(index[b]);
if (ak == bk) {
- return false;
+ return -1;
}
- if ( items[ak].parent < items[bk].parent ) {
- unlaceClass(bk);
- items[ak].parent += items[bk].parent;
+ int acx = ~(items[ak].parent);
+ int bcx = ~(items[bk].parent);
+
+ int rcx;
+
+ if (classes[acx].size > classes[bcx].size) {
+ classes[acx].size += classes[bcx].size;
items[bk].parent = ak;
+ unlaceClass(bcx);
+ rcx = acx;
} else {
- unlaceClass(ak);
- items[bk].parent += items[ak].parent;
+ classes[bcx].size += classes[acx].size;
items[ak].parent = bk;
+ unlaceClass(acx);
+ rcx = bcx;
}
spliceItems(ak, bk);
- return true;
+ return rcx;
}
- /// \brief Returns the size of the component of element \e a.
+ /// \brief Returns the size of the class.
///
- /// Returns the size of the component of element \e a.
- int size(const Item &item) const {
- return - items[repIndex(index[item])].parent;
+ /// Returns the size of the class.
+ int size(int cls) const {
+ return classes[cls].size;
}
- /// \brief Splits up the component of the element.
+ /// \brief Splits up the component.
///
- /// Splitting the component of the element into sigleton
- /// components (component of size one).
- void split(const Item &item) {
- int k = repIndex(index[item]);
- int idx = items[k].nextItem;
- while (idx != k) {
- int next = items[idx].nextItem;
-
- items[idx].parent = -1;
- items[idx].prevItem = idx;
- items[idx].nextItem = idx;
-
- items[idx].nextClass = firstClass;
- items[firstClass].prevClass = idx;
- firstClass = idx;
+ /// Splitting the component into singleton components (component
+ /// of size one).
+ void split(int cls) {
+ int fdx = classes[cls].firstItem;
+ int idx = items[fdx].next;
+ while (idx != fdx) {
+ int next = items[idx].next;
+ singletonItem(idx);
+
+ int cdx = newClass();
+ items[idx].parent = ~cdx;
+
+ laceClass(cdx);
+ classes[cdx].size = 1;
+ classes[cdx].firstItem = idx;
+
idx = next;
}
- items[idx].parent = -1;
- items[idx].prevItem = idx;
- items[idx].nextItem = idx;
-
- items[firstClass].prevClass = -1;
- }
+ items[idx].prev = idx;
+ items[idx].next = idx;
- /// \brief Sets the given element to the leader element of its component.
- ///
- /// Sets the given element to the leader element of its component.
- void makeRep(const Item &item) {
- int nk = index[item];
- int k = repIndex(nk);
- if (nk == k) return;
+ classes[~(items[idx].parent)].size = 1;
- if (items[k].prevClass != -1) {
- items[items[k].prevClass].nextClass = nk;
- } else {
- firstClass = nk;
- }
- if (items[k].nextClass != -1) {
- items[items[k].nextClass].prevClass = nk;
- }
-
- int idx = items[k].nextItem;
- while (idx != k) {
- items[idx].parent = nk;
- idx = items[idx].nextItem;
- }
-
- items[nk].parent = items[k].parent;
- items[k].parent = nk;
}
/// \brief Removes the given element from the structure.
@@ -405,124 +448,97 @@
///
/// \warning It is an error to remove an element which is not in
/// the structure.
- void erase(const Item &item) {
+ /// \warning This running time of this operation is proportional to the
+ /// number of the items in this class.
+ void erase(const Item& item) {
int idx = index[item];
- if (rep(idx)) {
- int k = idx;
- if (items[k].parent == -1) {
- unlaceClass(idx);
- return;
- } else {
- int nk = items[k].nextItem;
- if (items[k].prevClass != -1) {
- items[items[k].prevClass].nextClass = nk;
- } else {
- firstClass = nk;
- }
- if (items[k].nextClass != -1) {
- items[items[k].nextClass].prevClass = nk;
- }
-
- int l = items[k].nextItem;
- while (l != k) {
- items[l].parent = nk;
- l = items[l].nextItem;
- }
-
- items[nk].parent = items[k].parent + 1;
- }
+ int fdx = items[idx].next;
+
+ int cdx = classIndex(idx);
+ if (idx == fdx) {
+ unlaceClass(cdx);
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+ return;
} else {
-
- int k = repIndex(idx);
- idx = items[k].nextItem;
- while (idx != k) {
- items[idx].parent = k;
- idx = items[idx].nextItem;
- }
-
- ++items[k].parent;
+ classes[cdx].firstItem = fdx;
+ --classes[cdx].size;
+ items[fdx].parent = ~cdx;
+
+ unlaceItem(idx);
+ idx = items[fdx].next;
+ while (idx != fdx) {
+ items[idx].parent = fdx;
+ idx = items[idx].next;
+ }
+
}
- idx = index[item];
- items[items[idx].prevItem].nextItem = items[idx].nextItem;
- items[items[idx].nextItem].prevItem = items[idx].prevItem;
-
}
- /// \brief Moves the given element to another component.
- ///
- /// This method moves the element \e a from its component
- /// to the component of \e comp.
- /// If \e a and \e comp are in the same component then
- /// it returns false otherwise it returns true.
- bool move(const Item &item, const Item &comp) {
- if (repIndex(index[item]) == repIndex(index[comp])) return false;
- erase(item);
- insert(item, comp);
- return true;
- }
-
-
/// \brief Removes the component of the given element from the structure.
///
/// Removes the component of the given element from the structure.
///
/// \warning It is an error to give an element which is not in the
/// structure.
- void eraseClass(const Item &item) {
- unlaceClass(repIndex(index[item]));
+ void eraseClass(int cls) {
+ int fdx = classes[cls].firstItem;
+ unlaceClass(cls);
+ items[items[fdx].prev].next = firstFreeItem;
+ firstFreeItem = fdx;
}
/// \brief Lemon style iterator for the representant items.
///
/// ClassIt is a lemon style iterator for the components. It iterates
- /// on the representant items of the classes.
+ /// on the ids of the classes.
class ClassIt {
public:
/// \brief Constructor of the iterator
///
/// Constructor of the iterator
ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) {
- idx = unionFind->firstClass;
+ cdx = unionFind->firstClass;
}
/// \brief Constructor to get invalid iterator
///
/// Constructor to get invalid iterator
- ClassIt(Invalid) : unionFind(0), idx(-1) {}
+ ClassIt(Invalid) : unionFind(0), cdx(-1) {}
/// \brief Increment operator
///
/// It steps to the next representant item.
ClassIt& operator++() {
- idx = unionFind->items[idx].nextClass;
+ cdx = unionFind->classes[cdx].next;
return *this;
}
/// \brief Conversion operator
///
/// It converts the iterator to the current representant item.
- operator const Item&() const {
- return unionFind->items[idx].item;
+ operator int() const {
+ return cdx;
}
/// \brief Equality operator
///
/// Equality operator
bool operator==(const ClassIt& i) {
- return i.idx == idx;
+ return i.cdx == cdx;
}
/// \brief Inequality operator
///
/// Inequality operator
bool operator!=(const ClassIt& i) {
- return i.idx != idx;
+ return i.cdx != cdx;
}
private:
const UnionFindEnum* unionFind;
- int idx;
+ int cdx;
};
/// \brief Lemon style iterator for the items of a component.
@@ -545,8 +561,8 @@
///
/// Constructor of the iterator. The iterator iterates
/// on the class of the \c item.
- ItemIt(const UnionFindEnum& ufe, const Item& item) : unionFind(&ufe) {
- idx = unionFind->repIndex(unionFind->index[item]);
+ ItemIt(const UnionFindEnum& ufe, int cls) : unionFind(&ufe) {
+ fdx = idx = unionFind->classes[cls].firstItem;
}
/// \brief Constructor to get invalid iterator
@@ -558,8 +574,8 @@
///
/// It steps to the next item in the class.
ItemIt& operator++() {
- idx = unionFind->items[idx].nextItem;
- if (unionFind->rep(idx)) idx = -1;
+ idx = unionFind->items[idx].next;
+ if (idx == fdx) idx = -1;
return *this;
}
@@ -586,11 +602,310 @@
private:
const UnionFindEnum* unionFind;
- int idx;
+ int idx, fdx;
};
};
+ /// \ingroup auxdat
+ ///
+ /// \brief A \e Extend-Find data structure implementation which
+ /// is able to enumerate the components.
+ ///
+ /// The class implements an \e Extend-Find data structure which is
+ /// able to enumerate the components and the items in a
+ /// component. The data structure is a simplification of the
+ /// Union-Find structure, and it does not allow to merge two components.
+ ///
+ /// \pre You need to add all the elements by the \ref insert()
+ /// method.
+ template <typename _ItemIntMap>
+ class ExtendFindEnum {
+ public:
+
+ typedef _ItemIntMap ItemIntMap;
+ typedef typename ItemIntMap::Key Item;
+
+ private:
+
+ ItemIntMap& index;
+
+ struct ItemT {
+ int cls;
+ Item item;
+ int next, prev;
+ };
+
+ std::vector<ItemT> items;
+ int firstFreeItem;
+
+ struct ClassT {
+ int firstItem;
+ int next, prev;
+ };
+
+ std::vector<ClassT> classes;
+
+ int firstClass, firstFreeClass;
+
+ int newClass() {
+ if (firstFreeClass != -1) {
+ int cdx = firstFreeClass;
+ firstFreeClass = classes[cdx].next;
+ return cdx;
+ } else {
+ classes.push_back(ClassT());
+ return classes.size() - 1;
+ }
+ }
+
+ int newItem() {
+ if (firstFreeItem != -1) {
+ int idx = firstFreeItem;
+ firstFreeItem = items[idx].next;
+ return idx;
+ } else {
+ items.push_back(ItemT());
+ return items.size() - 1;
+ }
+ }
+
+ public:
+
+ /// \brief Constructor
+ ExtendFindEnum(ItemIntMap& _index)
+ : index(_index), items(), firstFreeItem(-1),
+ classes(), firstClass(-1), firstFreeClass(-1) {}
+
+ /// \brief Inserts the given element into a new component.
+ ///
+ /// This method creates a new component consisting only of the
+ /// given element.
+ int insert(const Item& item) {
+ int cdx = newClass();
+ classes[cdx].prev = -1;
+ classes[cdx].next = firstClass;
+ firstClass = cdx;
+
+ int idx = newItem();
+ items[idx].item = item;
+ items[idx].cls = cdx;
+ items[idx].prev = idx;
+ items[idx].next = idx;
+
+ classes[cdx].firstItem = idx;
+
+ index.set(item, idx);
+
+ return cdx;
+ }
+
+ /// \brief Inserts the given element into the given component.
+ ///
+ /// This methods inserts the element \e item a into the \e cls class.
+ void insert(const Item& item, int cls) {
+ int idx = newItem();
+ int rdx = classes[cls].firstItem;
+ items[idx].item = item;
+ items[idx].cls = cls;
+
+ items[idx].prev = rdx;
+ items[idx].next = items[rdx].next;
+ items[items[rdx].next].prev = idx;
+ items[rdx].next = idx;
+
+ index.set(item, idx);
+ }
+
+ /// \brief Clears the union-find data structure
+ ///
+ /// Erase each item from the data structure.
+ void clear() {
+ items.clear();
+ classes.clear;
+ firstClass = firstFreeClass = firstFreeItem = -1;
+ }
+
+ /// \brief Gives back the class of the \e item.
+ ///
+ /// Gives back the class of the \e item.
+ int find(const Item &item) const {
+ return items[index[item]].cls;
+ }
+
+ /// \brief Removes the given element from the structure.
+ ///
+ /// Removes the element from its component and if the component becomes
+ /// empty then removes that component from the component list.
+ ///
+ /// \warning It is an error to remove an element which is not in
+ /// the structure.
+ void erase(const Item &item) {
+ int idx = index[item];
+ int cdx = items[idx].cls;
+
+ if (idx == items[idx].next) {
+ if (classes[cdx].prev != -1) {
+ classes[classes[cdx].prev].next = classes[cdx].next;
+ } else {
+ firstClass = classes[cdx].next;
+ }
+ if (classes[cdx].next != -1) {
+ classes[classes[cdx].next].prev = classes[cdx].prev;
+ }
+ classes[cdx].next = firstFreeClass;
+ firstFreeClass = cdx;
+ } else {
+ classes[cdx].firstItem = items[idx].next;
+ items[items[idx].next].prev = items[idx].prev;
+ items[items[idx].prev].next = items[idx].next;
+ }
+ items[idx].next = firstFreeItem;
+ firstFreeItem = idx;
+
+ }
+
+
+ /// \brief Removes the component of the given element from the structure.
+ ///
+ /// Removes the component of the given element from the structure.
+ ///
+ /// \warning It is an error to give an element which is not in the
+ /// structure.
+ void eraseClass(int cdx) {
+ int idx = classes[cdx].firstItem;
+ items[items[idx].prev].next = firstFreeItem;
+ firstFreeItem = idx;
+
+ if (classes[cdx].prev != -1) {
+ classes[classes[cdx].prev].next = classes[cdx].next;
+ } else {
+ firstClass = classes[cdx].next;
+ }
+ if (classes[cdx].next != -1) {
+ classes[classes[cdx].next].prev = classes[cdx].prev;
+ }
+ classes[cdx].next = firstFreeClass;
+ firstFreeClass = cdx;
+ }
+
+ /// \brief Lemon style iterator for the classes.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the ids of classes.
+ class ClassIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator
+ ClassIt(const ExtendFindEnum& ufe) : extendFind(&ufe) {
+ cdx = extendFind->firstClass;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ClassIt(Invalid) : extendFind(0), cdx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next representant item.
+ ClassIt& operator++() {
+ cdx = extendFind->classes[cdx].next;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current class id.
+ operator int() const {
+ return cdx;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ClassIt& i) {
+ return i.cdx == cdx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ClassIt& i) {
+ return i.cdx != cdx;
+ }
+
+ private:
+ const ExtendFindEnum* extendFind;
+ int cdx;
+ };
+
+ /// \brief Lemon style iterator for the items of a component.
+ ///
+ /// ClassIt is a lemon style iterator for the components. It iterates
+ /// on the items of a class. By example if you want to iterate on
+ /// each items of each classes then you may write the next code.
+ ///\code
+ /// for (ClassIt cit(ufe); cit != INVALID; ++cit) {
+ /// std::cout << "Class: ";
+ /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) {
+ /// std::cout << toString(iit) << ' ' << std::endl;
+ /// }
+ /// std::cout << std::endl;
+ /// }
+ ///\endcode
+ class ItemIt {
+ public:
+ /// \brief Constructor of the iterator
+ ///
+ /// Constructor of the iterator. The iterator iterates
+ /// on the class of the \c item.
+ ItemIt(const ExtendFindEnum& ufe, int cls) : extendFind(&ufe) {
+ fdx = idx = extendFind->classes[cls].firstItem;
+ }
+
+ /// \brief Constructor to get invalid iterator
+ ///
+ /// Constructor to get invalid iterator
+ ItemIt(Invalid) : extendFind(0), idx(-1) {}
+
+ /// \brief Increment operator
+ ///
+ /// It steps to the next item in the class.
+ ItemIt& operator++() {
+ idx = extendFind->items[idx].next;
+ if (fdx == idx) idx = -1;
+ return *this;
+ }
+
+ /// \brief Conversion operator
+ ///
+ /// It converts the iterator to the current item.
+ operator const Item&() const {
+ return extendFind->items[idx].item;
+ }
+
+ /// \brief Equality operator
+ ///
+ /// Equality operator
+ bool operator==(const ItemIt& i) {
+ return i.idx == idx;
+ }
+
+ /// \brief Inequality operator
+ ///
+ /// Inequality operator
+ bool operator!=(const ItemIt& i) {
+ return i.idx != idx;
+ }
+
+ private:
+ const ExtendFindEnum* extendFind;
+ int idx, fdx;
+ };
+
+ };
//! @}
Modified: lemon/trunk/test/max_matching_test.cc
==============================================================================
--- lemon/trunk/test/max_matching_test.cc (original)
+++ lemon/trunk/test/max_matching_test.cc Tue Oct 30 21:21:10 2007
@@ -66,11 +66,12 @@
g.addEdge(nodes[6], nodes[12]);
MaxMatching<Graph> max_matching(g);
- max_matching.runEdmonds(0);
+ max_matching.init();
+ max_matching.startDense();
int s=0;
Graph::NodeMap<Node> mate(g,INVALID);
- max_matching.writeNMapNode(mate);
+ max_matching.mateMap(mate);
for(NodeIt v(g); v!=INVALID; ++v) {
if ( mate[v]!=INVALID ) ++s;
}
@@ -82,43 +83,42 @@
check ( size == max_matching.size(), "mate() returns a different size matching than max_matching.size()" );
- Graph::NodeMap<MaxMatching<Graph>::pos_enum> pos0(g);
- max_matching.writePos(pos0);
+ Graph::NodeMap<MaxMatching<Graph>::DecompType> pos0(g);
+ max_matching.decomposition(pos0);
- max_matching.resetMatching();
- max_matching.runEdmonds(1);
+ max_matching.init();
+ max_matching.startSparse();
s=0;
- max_matching.writeNMapNode(mate);
+ max_matching.mateMap(mate);
for(NodeIt v(g); v!=INVALID; ++v) {
if ( mate[v]!=INVALID ) ++s;
}
check ( int(s/2) == size, "The size does not equal!" );
- Graph::NodeMap<MaxMatching<Graph>::pos_enum> pos1(g);
- max_matching.writePos(pos1);
+ Graph::NodeMap<MaxMatching<Graph>::DecompType> pos1(g);
+ max_matching.decomposition(pos1);
max_matching.run();
s=0;
- max_matching.writeNMapNode(mate);
+ max_matching.mateMap(mate);
for(NodeIt v(g); v!=INVALID; ++v) {
if ( mate[v]!=INVALID ) ++s;
}
check ( int(s/2) == size, "The size does not equal!" );
- Graph::NodeMap<MaxMatching<Graph>::pos_enum> pos2(g);
- max_matching.writePos(pos2);
+ Graph::NodeMap<MaxMatching<Graph>::DecompType> pos2(g);
+ max_matching.decomposition(pos2);
- max_matching.resetMatching();
max_matching.run();
s=0;
- max_matching.writeNMapNode(mate);
+ max_matching.mateMap(mate);
for(NodeIt v(g); v!=INVALID; ++v) {
if ( mate[v]!=INVALID ) ++s;
}
check ( int(s/2) == size, "The size does not equal!" );
- Graph::NodeMap<MaxMatching<Graph>::pos_enum> pos(g);
- max_matching.writePos(pos);
+ Graph::NodeMap<MaxMatching<Graph>::DecompType> pos(g);
+ max_matching.decomposition(pos);
bool ismatching=true;
for(NodeIt v(g); v!=INVALID; ++v) {
@@ -139,8 +139,10 @@
bool noedge=true;
for(UEdgeIt e(g); e!=INVALID; ++e) {
- if ( (pos[g.target(e)]==max_matching.C && pos[g.source(e)]==max_matching.D) ||
- (pos[g.target(e)]==max_matching.D && pos[g.source(e)]==max_matching.C) )
+ if ( (pos[g.target(e)]==max_matching.C &&
+ pos[g.source(e)]==max_matching.D) ||
+ (pos[g.target(e)]==max_matching.D &&
+ pos[g.source(e)]==max_matching.C) )
noedge=false;
}
check ( noedge, "There are edges between D and C!" );
Modified: lemon/trunk/test/unionfind_test.cc
==============================================================================
--- lemon/trunk/test/unionfind_test.cc (original)
+++ lemon/trunk/test/unionfind_test.cc Tue Oct 30 21:21:10 2007
@@ -49,7 +49,7 @@
U.insert(1);
U.insert(2);
- check(U.join(1,2),"Test failed.");
+ check(U.join(1,2) != -1,"Test failed.");
U.insert(3);
U.insert(4);
@@ -57,66 +57,58 @@
U.insert(6);
U.insert(7);
- check(U.join(1,4),"Test failed.");
- check(!U.join(2,4),"Test failed.");
- check(U.join(3,5),"Test failed.");
-
- U.insert(8,5);
-
- check(U.size(4) == 3,"Test failed.");
- check(U.size(5) == 3,"Test failed.");
- check(U.size(6) == 1,"Test failed.");
- check(U.size(2) == 3,"Test failed.");
- U.insert(9);
- U.insert(10,9);
+ check(U.join(1,4) != -1,"Test failed.");
+ check(U.join(2,4) == -1,"Test failed.");
+ check(U.join(3,5) != -1,"Test failed.");
+
+
+ U.insert(8,U.find(5));
+
- check(U.join(8,10),"Test failed.");
+ check(U.size(U.find(4)) == 3,"Test failed.");
+ check(U.size(U.find(5)) == 3,"Test failed.");
+ check(U.size(U.find(6)) == 1,"Test failed.");
+ check(U.size(U.find(2)) == 3,"Test failed.");
+
+
+ U.insert(9);
+ U.insert(10,U.find(9));
- check(U.move(9,4),"Test failed.");
- check(!U.move(9,2),"Test failed.");
- check(U.size(4) == 4,"Test failed.");
- check(U.size(9) == 4,"Test failed.");
+ check(U.join(8,10) != -1,"Test failed.");
- check(U.move(5,6),"Test failed.");
- check(U.size(5) == 2,"Test failed.");
- check(U.size(8) == 3,"Test failed.");
+ check(U.size(U.find(4)) == 3,"Test failed.");
+ check(U.size(U.find(9)) == 5,"Test failed.");
- check(U.move(7,10),"Test failed.");
- check(U.size(7) == 4,"Test failed.");
+ check(U.size(U.find(8)) == 5,"Test failed.");
U.erase(9);
U.erase(1);
- check(U.size(4) == 2,"Test failed.");
- check(U.size(2) == 2,"Test failed.");
+ check(U.size(U.find(10)) == 4,"Test failed.");
+ check(U.size(U.find(2)) == 2,"Test failed.");
U.erase(6);
- U.split(8);
+ U.split(U.find(8));
- check(U.size(4) == 2,"Test failed.");
- check(U.size(3) == 1,"Test failed.");
- check(U.size(2) == 2,"Test failed.");
- check(U.join(3,4),"Test failed.");
- check(!U.join(2,4),"Test failed.");
+ check(U.size(U.find(4)) == 2,"Test failed.");
+ check(U.size(U.find(3)) == 1,"Test failed.");
+ check(U.size(U.find(2)) == 2,"Test failed.");
- check(U.size(4) == 3,"Test failed.");
- check(U.size(3) == 3,"Test failed.");
- check(U.size(2) == 3,"Test failed.");
- U.makeRep(4);
- U.makeRep(3);
- U.makeRep(2);
+ check(U.join(3,4) != -1,"Test failed.");
+ check(U.join(2,4) == -1,"Test failed.");
- check(U.size(4) == 3,"Test failed.");
- check(U.size(3) == 3,"Test failed.");
- check(U.size(2) == 3,"Test failed.");
+ check(U.size(U.find(4)) == 3,"Test failed.");
+ check(U.size(U.find(3)) == 3,"Test failed.");
+ check(U.size(U.find(2)) == 3,"Test failed.");
- U.eraseClass(4);
- U.eraseClass(7);
+ U.eraseClass(U.find(4));
+ U.eraseClass(U.find(7));
+ return 0;
}
More information about the Lemon-commits
mailing list