Do not install the documentation if configure was called with --disable-doc.
3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #ifndef LEMON_LIST_GRAPH_H
20 #define LEMON_LIST_GRAPH_H
24 ///\brief ListGraph, ListUGraph classes.
26 #include <lemon/bits/base_extender.h>
27 #include <lemon/bits/graph_extender.h>
29 #include <lemon/error.h>
40 int first_in, first_out;
46 int prev_in, prev_out;
47 int next_in, next_out;
50 std::vector<NodeT> nodes;
56 std::vector<EdgeT> edges;
62 typedef ListGraphBase Graph;
65 friend class ListGraphBase;
69 explicit Node(int pid) { id = pid;}
73 Node (Invalid) { id = -1; }
74 bool operator==(const Node& node) const {return id == node.id;}
75 bool operator!=(const Node& node) const {return id != node.id;}
76 bool operator<(const Node& node) const {return id < node.id;}
80 friend class ListGraphBase;
84 explicit Edge(int pid) { id = pid;}
88 Edge (Invalid) { id = -1; }
89 bool operator==(const Edge& edge) const {return id == edge.id;}
90 bool operator!=(const Edge& edge) const {return id != edge.id;}
91 bool operator<(const Edge& edge) const {return id < edge.id;}
97 : nodes(), first_node(-1),
98 first_free_node(-1), edges(), first_free_edge(-1) {}
105 int maxNodeId() const { return nodes.size()-1; }
111 int maxEdgeId() const { return edges.size()-1; }
113 Node source(Edge e) const { return Node(edges[e.id].source); }
114 Node target(Edge e) const { return Node(edges[e.id].target); }
117 void first(Node& node) const {
118 node.id = first_node;
121 void next(Node& node) const {
122 node.id = nodes[node.id].next;
126 void first(Edge& e) const {
129 n!=-1 && nodes[n].first_in == -1;
131 e.id = (n == -1) ? -1 : nodes[n].first_in;
134 void next(Edge& edge) const {
135 if (edges[edge.id].next_in != -1) {
136 edge.id = edges[edge.id].next_in;
139 for(n = nodes[edges[edge.id].target].next;
140 n!=-1 && nodes[n].first_in == -1;
142 edge.id = (n == -1) ? -1 : nodes[n].first_in;
146 void firstOut(Edge &e, const Node& v) const {
147 e.id = nodes[v.id].first_out;
149 void nextOut(Edge &e) const {
150 e.id=edges[e.id].next_out;
153 void firstIn(Edge &e, const Node& v) const {
154 e.id = nodes[v.id].first_in;
156 void nextIn(Edge &e) const {
157 e.id=edges[e.id].next_in;
161 static int id(Node v) { return v.id; }
162 static int id(Edge e) { return e.id; }
164 static Node nodeFromId(int id) { return Node(id);}
165 static Edge edgeFromId(int id) { return Edge(id);}
167 /// Adds a new node to the graph.
169 /// Adds a new node to the graph.
171 /// \warning It adds the new node to the front of the list.
172 /// (i.e. the lastly added node becomes the first.)
176 if(first_free_node==-1) {
178 nodes.push_back(NodeT());
181 first_free_node = nodes[n].next;
184 nodes[n].next = first_node;
185 if(first_node != -1) nodes[first_node].prev = n;
189 nodes[n].first_in = nodes[n].first_out = -1;
194 Edge addEdge(Node u, Node v) {
197 if (first_free_edge == -1) {
199 edges.push_back(EdgeT());
202 first_free_edge = edges[n].next_in;
205 edges[n].source = u.id;
206 edges[n].target = v.id;
208 edges[n].next_out = nodes[u.id].first_out;
209 if(nodes[u.id].first_out != -1) {
210 edges[nodes[u.id].first_out].prev_out = n;
213 edges[n].next_in = nodes[v.id].first_in;
214 if(nodes[v.id].first_in != -1) {
215 edges[nodes[v.id].first_in].prev_in = n;
218 edges[n].prev_in = edges[n].prev_out = -1;
220 nodes[u.id].first_out = nodes[v.id].first_in = n;
225 void erase(const Node& node) {
228 if(nodes[n].next != -1) {
229 nodes[nodes[n].next].prev = nodes[n].prev;
232 if(nodes[n].prev != -1) {
233 nodes[nodes[n].prev].next = nodes[n].next;
235 first_node = nodes[n].next;
238 nodes[n].next = first_free_node;
243 void erase(const Edge& edge) {
246 if(edges[n].next_in!=-1) {
247 edges[edges[n].next_in].prev_in = edges[n].prev_in;
250 if(edges[n].prev_in!=-1) {
251 edges[edges[n].prev_in].next_in = edges[n].next_in;
253 nodes[edges[n].target].first_in = edges[n].next_in;
257 if(edges[n].next_out!=-1) {
258 edges[edges[n].next_out].prev_out = edges[n].prev_out;
261 if(edges[n].prev_out!=-1) {
262 edges[edges[n].prev_out].next_out = edges[n].next_out;
264 nodes[edges[n].source].first_out = edges[n].next_out;
267 edges[n].next_in = first_free_edge;
275 first_node = first_free_node = first_free_edge = -1;
279 void changeTarget(Edge e, Node n)
281 if(edges[e.id].next_in != -1)
282 edges[edges[e.id].next_in].prev_in = edges[e.id].prev_in;
283 if(edges[e.id].prev_in != -1)
284 edges[edges[e.id].prev_in].next_in = edges[e.id].next_in;
285 else nodes[edges[e.id].target].first_in = edges[e.id].next_in;
286 if (nodes[n.id].first_in != -1) {
287 edges[nodes[n.id].first_in].prev_in = e.id;
289 edges[e.id].target = n.id;
290 edges[e.id].prev_in = -1;
291 edges[e.id].next_in = nodes[n.id].first_in;
292 nodes[n.id].first_in = e.id;
294 void changeSource(Edge e, Node n)
296 if(edges[e.id].next_out != -1)
297 edges[edges[e.id].next_out].prev_out = edges[e.id].prev_out;
298 if(edges[e.id].prev_out != -1)
299 edges[edges[e.id].prev_out].next_out = edges[e.id].next_out;
300 else nodes[edges[e.id].source].first_out = edges[e.id].next_out;
301 if (nodes[n.id].first_out != -1) {
302 edges[nodes[n.id].first_out].prev_out = e.id;
304 edges[e.id].source = n.id;
305 edges[e.id].prev_out = -1;
306 edges[e.id].next_out = nodes[n.id].first_out;
307 nodes[n.id].first_out = e.id;
312 typedef GraphExtender<ListGraphBase> ExtendedListGraphBase;
314 /// \addtogroup graphs
317 ///A list graph class.
319 ///This is a simple and fast graph implementation.
321 ///It conforms to the \ref concept::Graph "Graph concept" and it
322 ///also provides several additional useful extra functionalities.
323 ///The most of the member functions and nested classes are
324 ///documented only in the concept class.
325 ///\sa concept::Graph.
327 class ListGraph : public ExtendedListGraphBase {
330 typedef ExtendedListGraphBase Parent;
332 ///Add a new node to the graph.
334 /// \return the new node.
336 Node addNode() { return Parent::addNode(); }
338 ///Add a new edge to the graph.
340 ///Add a new edge to the graph with source node \c s
341 ///and target node \c t.
342 ///\return the new edge.
343 Edge addEdge(const Node& s, const Node& t) {
344 return Parent::addEdge(s, t);
347 /// Changes the target of \c e to \c n
349 /// Changes the target of \c e to \c n
351 ///\note The <tt>Edge</tt>s and <tt>OutEdgeIt</tt>s referencing
352 ///the changed edge remain valid. However <tt>InEdgeIt</tt>s are
354 ///\warning This functionality cannot be used together with the Snapshot
356 void changeTarget(Edge e, Node n) {
357 Parent::changeTarget(e,n);
359 /// Changes the source of \c e to \c n
361 /// Changes the source of \c e to \c n
363 ///\note The <tt>Edge</tt>s and <tt>InEdgeIt</tt>s referencing
364 ///the changed edge remain valid. However <tt>OutEdgeIt</tt>s are
366 ///\warning This functionality cannot be used together with the Snapshot
368 void changeSource(Edge e, Node n) {
369 Parent::changeSource(e,n);
372 /// Invert the direction of an edge.
374 ///\note The <tt>Edge</tt>s referencing the changed edge remain
375 ///valid. However <tt>OutEdgeIt</tt>s and <tt>InEdgeIt</tt>s are
377 ///\warning This functionality cannot be used together with the Snapshot
379 void reverseEdge(Edge e) {
381 changeTarget(e,source(e));
385 /// \brief Using this it is possible to avoid the superfluous memory
388 ///Using this it is possible to avoid the superfluous memory
389 ///allocation: if you know that the graph you want to build will
390 ///contain at least 10 million nodes then it is worth reserving
391 ///space for this amount before starting to build the graph.
392 void reserveNode(int n) { nodes.reserve(n); };
394 /// \brief Using this it is possible to avoid the superfluous memory
397 ///Using this it is possible to avoid the superfluous memory
398 ///allocation: see the \ref reserveNode function.
399 void reserveEdge(int n) { edges.reserve(n); };
402 ///Contract two nodes.
404 ///This function contracts two nodes.
406 ///Node \p b will be removed but instead of deleting
407 ///incident edges, they will be joined to \p a.
408 ///The last parameter \p r controls whether to remove loops. \c true
409 ///means that loops will be removed.
411 ///\note The <tt>Edge</tt>s
412 ///referencing a moved edge remain
413 ///valid. However <tt>InEdge</tt>s and <tt>OutEdge</tt>s
414 ///may be invalidated.
415 ///\warning This functionality cannot be used together with the Snapshot
417 void contract(Node a, Node b, bool r = true)
419 for(OutEdgeIt e(*this,b);e!=INVALID;) {
422 if(r && target(e)==a) erase(e);
423 else changeSource(e,a);
426 for(InEdgeIt e(*this,b);e!=INVALID;) {
429 if(r && source(e)==a) erase(e);
430 else changeTarget(e,a);
438 ///This function splits a node. First a new node is added to the graph,
439 ///then the source of each outgoing edge of \c n is moved to this new node.
440 ///If \c connect is \c true (this is the default value), then a new edge
441 ///from \c n to the newly created node is also added.
442 ///\return The newly created node.
444 ///\note The <tt>Edge</tt>s
445 ///referencing a moved edge remain
446 ///valid. However <tt>InEdge</tt>s and <tt>OutEdge</tt>s
447 ///may be invalidated.
448 ///\warning This functionality cannot be used together with the Snapshot
450 ///\todo It could be implemented in a bit faster way.
451 Node split(Node n, bool connect = true) {
453 for(OutEdgeIt e(*this,n);e!=INVALID;) {
459 if (connect) addEdge(n,b);
465 ///This function splits an edge. First a new node \c b is added to
466 ///the graph, then the original edge is re-targeted to \c
467 ///b. Finally an edge from \c b to the original target is added.
468 ///\return The newly created node.
469 ///\warning This functionality
470 ///cannot be used together with the Snapshot feature.
473 addEdge(b,target(e));
478 /// \brief Class to make a snapshot of the graph and restore
481 /// Class to make a snapshot of the graph and to restore it
484 /// The newly added nodes and edges can be removed using the
485 /// restore() function.
487 /// \warning Edge and node deletions cannot be restored.
491 class UnsupportedOperation : public LogicError {
493 virtual const char* exceptionName() const {
494 return "lemon::ListGraph::Snapshot::UnsupportedOperation";
501 typedef Parent::NodeNotifier NodeNotifier;
503 class NodeObserverProxy : public NodeNotifier::ObserverBase {
506 NodeObserverProxy(Snapshot& _snapshot)
507 : snapshot(_snapshot) {}
509 using NodeNotifier::ObserverBase::attach;
510 using NodeNotifier::ObserverBase::detach;
511 using NodeNotifier::ObserverBase::attached;
515 virtual void add(const Node& node) {
516 snapshot.addNode(node);
518 virtual void add(const std::vector<Node>& nodes) {
519 for (int i = nodes.size() - 1; i >= 0; ++i) {
520 snapshot.addNode(nodes[i]);
523 virtual void erase(const Node& node) {
524 snapshot.eraseNode(node);
526 virtual void erase(const std::vector<Node>& nodes) {
527 for (int i = 0; i < (int)nodes.size(); ++i) {
528 if (!snapshot.eraseNode(nodes[i])) break;
531 virtual void build() {
532 NodeNotifier* notifier = getNotifier();
534 std::vector<Node> nodes;
535 for (notifier->first(node); node != INVALID; notifier->next(node)) {
536 nodes.push_back(node);
538 for (int i = nodes.size() - 1; i >= 0; --i) {
539 snapshot.addNode(nodes[i]);
542 virtual void clear() {
543 NodeNotifier* notifier = getNotifier();
545 for (notifier->first(node); node != INVALID; notifier->next(node)) {
546 if (!snapshot.eraseNode(node)) break;
553 class EdgeObserverProxy : public EdgeNotifier::ObserverBase {
556 EdgeObserverProxy(Snapshot& _snapshot)
557 : snapshot(_snapshot) {}
559 using EdgeNotifier::ObserverBase::attach;
560 using EdgeNotifier::ObserverBase::detach;
561 using EdgeNotifier::ObserverBase::attached;
565 virtual void add(const Edge& edge) {
566 snapshot.addEdge(edge);
568 virtual void add(const std::vector<Edge>& edges) {
569 for (int i = edges.size() - 1; i >= 0; ++i) {
570 snapshot.addEdge(edges[i]);
573 virtual void erase(const Edge& edge) {
574 snapshot.eraseEdge(edge);
576 virtual void erase(const std::vector<Edge>& edges) {
577 for (int i = 0; i < (int)edges.size(); ++i) {
578 if (!snapshot.eraseEdge(edges[i])) break;
581 virtual void build() {
582 EdgeNotifier* notifier = getNotifier();
584 std::vector<Edge> edges;
585 for (notifier->first(edge); edge != INVALID; notifier->next(edge)) {
586 edges.push_back(edge);
588 for (int i = edges.size() - 1; i >= 0; --i) {
589 snapshot.addEdge(edges[i]);
592 virtual void clear() {
593 EdgeNotifier* notifier = getNotifier();
595 for (notifier->first(edge); edge != INVALID; notifier->next(edge)) {
596 if (!snapshot.eraseEdge(edge)) break;
605 NodeObserverProxy node_observer_proxy;
606 EdgeObserverProxy edge_observer_proxy;
608 std::list<Node> added_nodes;
609 std::list<Edge> added_edges;
612 void addNode(const Node& node) {
613 added_nodes.push_front(node);
615 bool eraseNode(const Node& node) {
616 std::list<Node>::iterator it =
617 std::find(added_nodes.begin(), added_nodes.end(), node);
618 if (it == added_nodes.end()) {
622 added_nodes.erase(it);
627 void addEdge(const Edge& edge) {
628 added_edges.push_front(edge);
630 bool eraseEdge(const Edge& edge) {
631 std::list<Edge>::iterator it =
632 std::find(added_edges.begin(), added_edges.end(), edge);
633 if (it == added_edges.end()) {
637 added_edges.erase(it);
642 void attach(ListGraph &_graph) {
644 node_observer_proxy.attach(graph->getNotifier(Node()));
645 edge_observer_proxy.attach(graph->getNotifier(Edge()));
649 node_observer_proxy.detach();
650 edge_observer_proxy.detach();
661 /// \brief Default constructur.
663 /// Default constructor.
664 /// To actually make a snapshot you must call save().
666 : graph(0), node_observer_proxy(*this),
667 edge_observer_proxy(*this) {}
669 /// \brief Constructor that immediately makes a snapshot.
671 /// This constructor immediately makes a snapshot of the graph.
672 /// \param _graph The graph we make a snapshot of.
673 Snapshot(ListGraph &_graph)
674 : node_observer_proxy(*this),
675 edge_observer_proxy(*this) {
679 /// \brief Make a snapshot.
681 /// Make a snapshot of the graph.
683 /// This function can be called more than once. In case of a repeated
684 /// call, the previous snapshot gets lost.
685 /// \param _graph The graph we make the snapshot of.
686 void save(ListGraph &_graph) {
691 /// \brief Undo the changes until the last snapshot.
693 /// Undo the changes until the last snapshot created by save().
696 while(!added_edges.empty()) {
697 graph->erase(added_edges.front());
698 added_edges.pop_front();
700 while(!added_nodes.empty()) {
701 graph->erase(added_nodes.front());
702 added_nodes.pop_front();
706 /// \brief Gives back true when the snapshot is valid.
708 /// Gives back true when the snapshot is valid.
710 return node_observer_proxy.attached();
718 /**************** Undirected List Graph ****************/
720 typedef UGraphExtender<UndirGraphExtender<ListGraphBase> >
721 ExtendedListUGraphBase;
723 /// \addtogroup graphs
726 ///An undirected list graph class.
728 ///This is a simple and fast undirected graph implementation.
730 ///It conforms to the
731 ///\ref concept::UGraph "UGraph concept".
733 ///\sa concept::UGraph.
735 ///\todo Snapshot, reverseEdge(), changeTarget(), changeSource(), contract()
736 ///haven't been implemented yet.
738 class ListUGraph : public ExtendedListUGraphBase {
740 typedef ExtendedListUGraphBase Parent;
741 /// \brief Add a new node to the graph.
743 /// \return the new node.
745 Node addNode() { return Parent::addNode(); }
747 /// \brief Add a new edge to the graph.
749 /// Add a new edge to the graph with source node \c s
750 /// and target node \c t.
751 /// \return the new undirected edge.
752 UEdge addEdge(const Node& s, const Node& t) {
753 return Parent::addEdge(s, t);
755 /// \brief Changes the target of \c e to \c n
757 /// Changes the target of \c e to \c n
759 /// \note The <tt>Edge</tt>'s and <tt>OutEdge</tt>'s
760 /// referencing the changed edge remain
761 /// valid. However <tt>InEdge</tt>'s are invalidated.
762 void changeTarget(UEdge e, Node n) {
763 Parent::changeTarget(e,n);
765 /// Changes the source of \c e to \c n
767 /// Changes the source of \c e to \c n
769 ///\note The <tt>Edge</tt>'s and <tt>InEdge</tt>'s
770 ///referencing the changed edge remain
771 ///valid. However <tt>OutEdge</tt>'s are invalidated.
772 void changeSource(UEdge e, Node n) {
773 Parent::changeSource(e,n);
775 /// \brief Contract two nodes.
777 /// This function contracts two nodes.
779 /// Node \p b will be removed but instead of deleting
780 /// its neighboring edges, they will be joined to \p a.
781 /// The last parameter \p r controls whether to remove loops. \c true
782 /// means that loops will be removed.
784 /// \note The <tt>Edge</tt>s
785 /// referencing a moved edge remain
787 void contract(Node a, Node b, bool r = true) {
788 for(IncEdgeIt e(*this, b); e!=INVALID;) {
789 IncEdgeIt f = e; ++f;
790 if (r && runningNode(e) == a) {
792 } else if (source(e) == b) {
804 class ListBpUGraphBase {
807 class NodeSetError : public LogicError {
808 virtual const char* exceptionName() const {
809 return "lemon::ListBpUGraph::NodeSetError";
816 int first_edge, prev, next;
820 int aNode, prev_out, next_out;
821 int bNode, prev_in, next_in;
824 std::vector<NodeT> aNodes;
825 std::vector<NodeT> bNodes;
827 std::vector<UEdgeT> edges;
830 int first_free_anode;
833 int first_free_bnode;
840 friend class ListBpUGraphBase;
844 explicit Node(int _id) : id(_id) {}
847 Node(Invalid) { id = -1; }
848 bool operator==(const Node i) const {return id==i.id;}
849 bool operator!=(const Node i) const {return id!=i.id;}
850 bool operator<(const Node i) const {return id<i.id;}
854 friend class ListBpUGraphBase;
858 explicit UEdge(int _id) { id = _id;}
861 UEdge (Invalid) { id = -1; }
862 bool operator==(const UEdge i) const {return id==i.id;}
863 bool operator!=(const UEdge i) const {return id!=i.id;}
864 bool operator<(const UEdge i) const {return id<i.id;}
868 : first_anode(-1), first_free_anode(-1),
869 first_bnode(-1), first_free_bnode(-1),
870 first_free_edge(-1) {}
872 void firstANode(Node& node) const {
873 node.id = first_anode != -1 ? (first_anode << 1) : -1;
875 void nextANode(Node& node) const {
876 node.id = aNodes[node.id >> 1].next;
879 void firstBNode(Node& node) const {
880 node.id = first_bnode != -1 ? (first_bnode << 1) + 1 : -1;
882 void nextBNode(Node& node) const {
883 node.id = bNodes[node.id >> 1].next;
886 void first(Node& node) const {
887 if (first_anode != -1) {
888 node.id = (first_anode << 1);
889 } else if (first_bnode != -1) {
890 node.id = (first_bnode << 1) + 1;
895 void next(Node& node) const {
897 node.id = aNodes[node.id >> 1].next;
899 if (first_bnode != -1) {
900 node.id = (first_bnode << 1) + 1;
904 node.id = bNodes[node.id >> 1].next;
908 void first(UEdge& edge) const {
909 int aNodeId = first_anode;
910 while (aNodeId != -1 && aNodes[aNodeId].first_edge == -1) {
911 aNodeId = aNodes[aNodeId].next != -1 ?
912 aNodes[aNodeId].next >> 1 : -1;
915 edge.id = aNodes[aNodeId].first_edge;
920 void next(UEdge& edge) const {
921 int aNodeId = edges[edge.id].aNode >> 1;
922 edge.id = edges[edge.id].next_out;
924 aNodeId = aNodes[aNodeId].next != -1 ?
925 aNodes[aNodeId].next >> 1 : -1;
926 while (aNodeId != -1 && aNodes[aNodeId].first_edge == -1) {
927 aNodeId = aNodes[aNodeId].next != -1 ?
928 aNodes[aNodeId].next >> 1 : -1;
931 edge.id = aNodes[aNodeId].first_edge;
938 void firstFromANode(UEdge& edge, const Node& node) const {
939 LEMON_ASSERT((node.id & 1) == 0, NodeSetError());
940 edge.id = aNodes[node.id >> 1].first_edge;
942 void nextFromANode(UEdge& edge) const {
943 edge.id = edges[edge.id].next_out;
946 void firstFromBNode(UEdge& edge, const Node& node) const {
947 LEMON_ASSERT((node.id & 1) == 1, NodeSetError());
948 edge.id = bNodes[node.id >> 1].first_edge;
950 void nextFromBNode(UEdge& edge) const {
951 edge.id = edges[edge.id].next_in;
954 static int id(const Node& node) {
957 static Node nodeFromId(int id) {
960 int maxNodeId() const {
961 return aNodes.size() > bNodes.size() ?
962 aNodes.size() * 2 - 2 : bNodes.size() * 2 - 1;
965 static int id(const UEdge& edge) {
968 static UEdge uEdgeFromId(int id) {
971 int maxUEdgeId() const {
975 static int aNodeId(const Node& node) {
978 static Node fromANodeId(int id) {
979 return Node(id << 1);
981 int maxANodeId() const {
982 return aNodes.size();
985 static int bNodeId(const Node& node) {
988 static Node fromBNodeId(int id) {
989 return Node((id << 1) + 1);
991 int maxBNodeId() const {
992 return bNodes.size();
995 Node aNode(const UEdge& edge) const {
996 return Node(edges[edge.id].aNode);
998 Node bNode(const UEdge& edge) const {
999 return Node(edges[edge.id].bNode);
1002 static bool aNode(const Node& node) {
1003 return (node.id & 1) == 0;
1006 static bool bNode(const Node& node) {
1007 return (node.id & 1) == 1;
1012 if (first_free_anode == -1) {
1013 aNodeId = aNodes.size();
1014 aNodes.push_back(NodeT());
1016 aNodeId = first_free_anode;
1017 first_free_anode = aNodes[first_free_anode].next;
1019 if (first_anode != -1) {
1020 aNodes[aNodeId].next = first_anode << 1;
1021 aNodes[first_anode].prev = aNodeId << 1;
1023 aNodes[aNodeId].next = -1;
1025 aNodes[aNodeId].prev = -1;
1026 first_anode = aNodeId;
1027 aNodes[aNodeId].first_edge = -1;
1028 return Node(aNodeId << 1);
1033 if (first_free_bnode == -1) {
1034 bNodeId = bNodes.size();
1035 bNodes.push_back(NodeT());
1037 bNodeId = first_free_bnode;
1038 first_free_bnode = bNodes[first_free_bnode].next;
1040 if (first_bnode != -1) {
1041 bNodes[bNodeId].next = (first_bnode << 1) + 1;
1042 bNodes[first_bnode].prev = (bNodeId << 1) + 1;
1044 bNodes[bNodeId].next = -1;
1046 first_bnode = bNodeId;
1047 bNodes[bNodeId].first_edge = -1;
1048 return Node((bNodeId << 1) + 1);
1051 UEdge addEdge(const Node& source, const Node& target) {
1052 LEMON_ASSERT(((source.id ^ target.id) & 1) == 1, NodeSetError());
1054 if (first_free_edge != -1) {
1055 edgeId = first_free_edge;
1056 first_free_edge = edges[edgeId].next_out;
1058 edgeId = edges.size();
1059 edges.push_back(UEdgeT());
1061 if ((source.id & 1) == 0) {
1062 edges[edgeId].aNode = source.id;
1063 edges[edgeId].bNode = target.id;
1065 edges[edgeId].aNode = target.id;
1066 edges[edgeId].bNode = source.id;
1068 edges[edgeId].next_out = aNodes[edges[edgeId].aNode >> 1].first_edge;
1069 edges[edgeId].prev_out = -1;
1070 if (aNodes[edges[edgeId].aNode >> 1].first_edge != -1) {
1071 edges[aNodes[edges[edgeId].aNode >> 1].first_edge].prev_out = edgeId;
1073 aNodes[edges[edgeId].aNode >> 1].first_edge = edgeId;
1074 edges[edgeId].next_in = bNodes[edges[edgeId].bNode >> 1].first_edge;
1075 edges[edgeId].prev_in = -1;
1076 if (bNodes[edges[edgeId].bNode >> 1].first_edge != -1) {
1077 edges[bNodes[edges[edgeId].bNode >> 1].first_edge].prev_in = edgeId;
1079 bNodes[edges[edgeId].bNode >> 1].first_edge = edgeId;
1080 return UEdge(edgeId);
1083 void erase(const Node& node) {
1085 int aNodeId = node.id >> 1;
1086 if (aNodes[aNodeId].prev != -1) {
1087 aNodes[aNodes[aNodeId].prev >> 1].next = aNodes[aNodeId].next;
1089 first_anode = aNodes[aNodeId].next >> 1;
1091 if (aNodes[aNodeId].next != -1) {
1092 aNodes[aNodes[aNodeId].next >> 1].prev = aNodes[aNodeId].prev;
1094 aNodes[aNodeId].next = first_free_anode;
1095 first_free_anode = aNodeId;
1097 int bNodeId = node.id >> 1;
1098 if (bNodes[bNodeId].prev != -1) {
1099 bNodes[bNodes[bNodeId].prev >> 1].next = bNodes[bNodeId].next;
1101 first_bnode = bNodes[bNodeId].next >> 1;
1103 if (bNodes[bNodeId].next != -1) {
1104 bNodes[bNodes[bNodeId].next >> 1].prev = bNodes[bNodeId].prev;
1106 bNodes[bNodeId].next = first_free_bnode;
1107 first_free_bnode = bNodeId;
1111 void erase(const UEdge& edge) {
1113 if (edges[edge.id].prev_out != -1) {
1114 edges[edges[edge.id].prev_out].next_out = edges[edge.id].next_out;
1116 aNodes[edges[edge.id].aNode >> 1].first_edge = edges[edge.id].next_out;
1118 if (edges[edge.id].next_out != -1) {
1119 edges[edges[edge.id].next_out].prev_out = edges[edge.id].prev_out;
1122 if (edges[edge.id].prev_in != -1) {
1123 edges[edges[edge.id].prev_in].next_in = edges[edge.id].next_in;
1125 bNodes[edges[edge.id].bNode >> 1].first_edge = edges[edge.id].next_in;
1127 if (edges[edge.id].next_in != -1) {
1128 edges[edges[edge.id].next_in].prev_in = edges[edge.id].prev_in;
1131 edges[edge.id].next_out = first_free_edge;
1132 first_free_edge = edge.id;
1140 first_free_anode = -1;
1142 first_free_bnode = -1;
1143 first_free_edge = -1;
1149 typedef BpUGraphExtender< ListBpUGraphBase > ExtendedListBpUGraphBase;
1153 /// \brief A smart bipartite undirected graph class.
1155 /// This is a bipartite undirected graph implementation.
1156 /// It is conforms to the \ref concept::BpUGraph "BpUGraph concept".
1157 /// \sa concept::BpUGraph.
1159 class ListBpUGraph : public ExtendedListBpUGraphBase {};