1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2009
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_HAO_ORLIN_H
20 #define LEMON_HAO_ORLIN_H
26 #include <lemon/maps.h>
27 #include <lemon/core.h>
28 #include <lemon/tolerance.h>
32 /// \brief Implementation of the Hao-Orlin algorithm.
34 /// Implementation of the Hao-Orlin algorithm class for testing network
41 /// \brief %Hao-Orlin algorithm to find a minimum cut in directed graphs.
43 /// Hao-Orlin calculates a minimum cut in a directed graph
44 /// \f$D=(V,A)\f$. It takes a fixed node \f$ source \in V \f$ and
45 /// consists of two phases: in the first phase it determines a
46 /// minimum cut with \f$ source \f$ on the source-side (i.e. a set
47 /// \f$ X\subsetneq V \f$ with \f$ source \in X \f$ and minimal
48 /// out-degree) and in the second phase it determines a minimum cut
49 /// with \f$ source \f$ on the sink-side (i.e. a set
50 /// \f$ X\subsetneq V \f$ with \f$ source \notin X \f$ and minimal
51 /// out-degree). Obviously, the smaller of these two cuts will be a
52 /// minimum cut of \f$ D \f$. The algorithm is a modified
53 /// push-relabel preflow algorithm and our implementation calculates
54 /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the
55 /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. The
56 /// purpose of such algorithm is testing network reliability. For an
57 /// undirected graph you can run just the first phase of the
58 /// algorithm or you can use the algorithm of Nagamochi and Ibaraki
59 /// which solves the undirected problem in
60 /// \f$ O(nm + n^2 \log n) \f$ time: it is implemented in the
61 /// NagamochiIbaraki algorithm class.
63 /// \param GR The digraph class the algorithm runs on.
64 /// \param CAP An arc map of capacities which can be any numreric type.
65 /// The default type is \ref concepts::Digraph::ArcMap "GR::ArcMap<int>".
66 /// \param TOL Tolerance class for handling inexact computations. The
67 /// default tolerance type is \ref Tolerance "Tolerance<CAP::Value>".
69 template <typename GR, typename CAP, typename TOL>
71 template <typename GR,
72 typename CAP = typename GR::template ArcMap<int>,
73 typename TOL = Tolerance<typename CAP::Value> >
79 typedef CAP CapacityMap;
80 typedef TOL Tolerance;
82 typedef typename CapacityMap::Value Value;
84 TEMPLATE_GRAPH_TYPEDEFS(Digraph);
86 const Digraph& _graph;
87 const CapacityMap* _capacity;
89 typedef typename Digraph::template ArcMap<Value> FlowMap;
96 // Bucketing structure
97 std::vector<Node> _first, _last;
98 typename Digraph::template NodeMap<Node>* _next;
99 typename Digraph::template NodeMap<Node>* _prev;
100 typename Digraph::template NodeMap<bool>* _active;
101 typename Digraph::template NodeMap<int>* _bucket;
103 std::vector<bool> _dormant;
105 std::list<std::list<int> > _sets;
106 std::list<int>::iterator _highest;
108 typedef typename Digraph::template NodeMap<Value> ExcessMap;
111 typedef typename Digraph::template NodeMap<bool> SourceSetMap;
112 SourceSetMap* _source_set;
116 typedef typename Digraph::template NodeMap<bool> MinCutMap;
117 MinCutMap* _min_cut_map;
119 Tolerance _tolerance;
123 /// \brief Constructor
125 /// Constructor of the algorithm class.
126 HaoOrlin(const Digraph& graph, const CapacityMap& capacity,
127 const Tolerance& tolerance = Tolerance()) :
128 _graph(graph), _capacity(&capacity), _flow(0), _source(),
129 _node_num(), _first(), _last(), _next(0), _prev(0),
130 _active(0), _bucket(0), _dormant(), _sets(), _highest(),
131 _excess(0), _source_set(0), _min_cut(), _min_cut_map(0),
132 _tolerance(tolerance) {}
163 void activate(const Node& i) {
164 _active->set(i, true);
166 int bucket = (*_bucket)[i];
168 if ((*_prev)[i] == INVALID || (*_active)[(*_prev)[i]]) return;
170 _next->set((*_prev)[i], (*_next)[i]);
171 if ((*_next)[i] != INVALID) {
172 _prev->set((*_next)[i], (*_prev)[i]);
174 _last[bucket] = (*_prev)[i];
177 _next->set(i, _first[bucket]);
178 _prev->set(_first[bucket], i);
179 _prev->set(i, INVALID);
183 void deactivate(const Node& i) {
184 _active->set(i, false);
185 int bucket = (*_bucket)[i];
187 if ((*_next)[i] == INVALID || !(*_active)[(*_next)[i]]) return;
190 _prev->set((*_next)[i], (*_prev)[i]);
191 if ((*_prev)[i] != INVALID) {
192 _next->set((*_prev)[i], (*_next)[i]);
194 _first[bucket] = (*_next)[i];
197 _prev->set(i, _last[bucket]);
198 _next->set(_last[bucket], i);
199 _next->set(i, INVALID);
203 void addItem(const Node& i, int bucket) {
204 (*_bucket)[i] = bucket;
205 if (_last[bucket] != INVALID) {
206 _prev->set(i, _last[bucket]);
207 _next->set(_last[bucket], i);
208 _next->set(i, INVALID);
211 _prev->set(i, INVALID);
213 _next->set(i, INVALID);
218 void findMinCutOut() {
220 for (NodeIt n(_graph); n != INVALID; ++n) {
224 for (ArcIt a(_graph); a != INVALID; ++a) {
229 std::vector<Node> queue(_node_num);
230 int qfirst = 0, qlast = 0, qsep = 0;
233 typename Digraph::template NodeMap<bool> reached(_graph, false);
235 reached.set(_source, true);
236 bool first_set = true;
238 for (NodeIt t(_graph); t != INVALID; ++t) {
239 if (reached[t]) continue;
240 _sets.push_front(std::list<int>());
243 reached.set(t, true);
245 while (qfirst != qlast) {
246 if (qsep == qfirst) {
248 _sets.front().push_front(bucket_num);
249 _dormant[bucket_num] = !first_set;
250 _first[bucket_num] = _last[bucket_num] = INVALID;
254 Node n = queue[qfirst++];
255 addItem(n, bucket_num);
257 for (InArcIt a(_graph, n); a != INVALID; ++a) {
258 Node u = _graph.source(a);
259 if (!reached[u] && _tolerance.positive((*_capacity)[a])) {
260 reached.set(u, true);
269 _bucket->set(_source, 0);
272 _source_set->set(_source, true);
274 Node target = _last[_sets.back().back()];
276 for (OutArcIt a(_graph, _source); a != INVALID; ++a) {
277 if (_tolerance.positive((*_capacity)[a])) {
278 Node u = _graph.target(a);
279 _flow->set(a, (*_capacity)[a]);
280 _excess->set(u, (*_excess)[u] + (*_capacity)[a]);
281 if (!(*_active)[u] && u != _source) {
287 if ((*_active)[target]) {
291 _highest = _sets.back().begin();
292 while (_highest != _sets.back().end() &&
293 !(*_active)[_first[*_highest]]) {
299 while (_highest != _sets.back().end()) {
300 Node n = _first[*_highest];
301 Value excess = (*_excess)[n];
302 int next_bucket = _node_num;
305 if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
308 under_bucket = *(++std::list<int>::iterator(_highest));
311 for (OutArcIt a(_graph, n); a != INVALID; ++a) {
312 Node v = _graph.target(a);
313 if (_dormant[(*_bucket)[v]]) continue;
314 Value rem = (*_capacity)[a] - (*_flow)[a];
315 if (!_tolerance.positive(rem)) continue;
316 if ((*_bucket)[v] == under_bucket) {
317 if (!(*_active)[v] && v != target) {
320 if (!_tolerance.less(rem, excess)) {
321 _flow->set(a, (*_flow)[a] + excess);
322 _excess->set(v, (*_excess)[v] + excess);
327 _excess->set(v, (*_excess)[v] + rem);
328 _flow->set(a, (*_capacity)[a]);
330 } else if (next_bucket > (*_bucket)[v]) {
331 next_bucket = (*_bucket)[v];
335 for (InArcIt a(_graph, n); a != INVALID; ++a) {
336 Node v = _graph.source(a);
337 if (_dormant[(*_bucket)[v]]) continue;
338 Value rem = (*_flow)[a];
339 if (!_tolerance.positive(rem)) continue;
340 if ((*_bucket)[v] == under_bucket) {
341 if (!(*_active)[v] && v != target) {
344 if (!_tolerance.less(rem, excess)) {
345 _flow->set(a, (*_flow)[a] - excess);
346 _excess->set(v, (*_excess)[v] + excess);
351 _excess->set(v, (*_excess)[v] + rem);
354 } else if (next_bucket > (*_bucket)[v]) {
355 next_bucket = (*_bucket)[v];
361 _excess->set(n, excess);
364 if ((*_next)[n] == INVALID) {
365 typename std::list<std::list<int> >::iterator new_set =
366 _sets.insert(--_sets.end(), std::list<int>());
367 new_set->splice(new_set->end(), _sets.back(),
368 _sets.back().begin(), ++_highest);
369 for (std::list<int>::iterator it = new_set->begin();
370 it != new_set->end(); ++it) {
371 _dormant[*it] = true;
373 while (_highest != _sets.back().end() &&
374 !(*_active)[_first[*_highest]]) {
377 } else if (next_bucket == _node_num) {
378 _first[(*_bucket)[n]] = (*_next)[n];
379 _prev->set((*_next)[n], INVALID);
381 std::list<std::list<int> >::iterator new_set =
382 _sets.insert(--_sets.end(), std::list<int>());
384 new_set->push_front(bucket_num);
385 _bucket->set(n, bucket_num);
386 _first[bucket_num] = _last[bucket_num] = n;
387 _next->set(n, INVALID);
388 _prev->set(n, INVALID);
389 _dormant[bucket_num] = true;
392 while (_highest != _sets.back().end() &&
393 !(*_active)[_first[*_highest]]) {
397 _first[*_highest] = (*_next)[n];
398 _prev->set((*_next)[n], INVALID);
400 while (next_bucket != *_highest) {
404 if (_highest == _sets.back().begin()) {
405 _sets.back().push_front(bucket_num);
406 _dormant[bucket_num] = false;
407 _first[bucket_num] = _last[bucket_num] = INVALID;
412 _bucket->set(n, *_highest);
413 _next->set(n, _first[*_highest]);
414 if (_first[*_highest] != INVALID) {
415 _prev->set(_first[*_highest], n);
417 _last[*_highest] = n;
419 _first[*_highest] = n;
424 if (!(*_active)[_first[*_highest]]) {
426 if (_highest != _sets.back().end() &&
427 !(*_active)[_first[*_highest]]) {
428 _highest = _sets.back().end();
434 if ((*_excess)[target] < _min_cut) {
435 _min_cut = (*_excess)[target];
436 for (NodeIt i(_graph); i != INVALID; ++i) {
437 _min_cut_map->set(i, true);
439 for (std::list<int>::iterator it = _sets.back().begin();
440 it != _sets.back().end(); ++it) {
441 Node n = _first[*it];
442 while (n != INVALID) {
443 _min_cut_map->set(n, false);
451 if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) {
452 if ((*_next)[target] == INVALID) {
453 _last[(*_bucket)[target]] = (*_prev)[target];
454 new_target = (*_prev)[target];
456 _prev->set((*_next)[target], (*_prev)[target]);
457 new_target = (*_next)[target];
459 if ((*_prev)[target] == INVALID) {
460 _first[(*_bucket)[target]] = (*_next)[target];
462 _next->set((*_prev)[target], (*_next)[target]);
465 _sets.back().pop_back();
466 if (_sets.back().empty()) {
470 for (std::list<int>::iterator it = _sets.back().begin();
471 it != _sets.back().end(); ++it) {
472 _dormant[*it] = false;
475 new_target = _last[_sets.back().back()];
478 _bucket->set(target, 0);
480 _source_set->set(target, true);
481 for (OutArcIt a(_graph, target); a != INVALID; ++a) {
482 Value rem = (*_capacity)[a] - (*_flow)[a];
483 if (!_tolerance.positive(rem)) continue;
484 Node v = _graph.target(a);
485 if (!(*_active)[v] && !(*_source_set)[v]) {
488 _excess->set(v, (*_excess)[v] + rem);
489 _flow->set(a, (*_capacity)[a]);
492 for (InArcIt a(_graph, target); a != INVALID; ++a) {
493 Value rem = (*_flow)[a];
494 if (!_tolerance.positive(rem)) continue;
495 Node v = _graph.source(a);
496 if (!(*_active)[v] && !(*_source_set)[v]) {
499 _excess->set(v, (*_excess)[v] + rem);
504 if ((*_active)[target]) {
508 _highest = _sets.back().begin();
509 while (_highest != _sets.back().end() &&
510 !(*_active)[_first[*_highest]]) {
517 void findMinCutIn() {
519 for (NodeIt n(_graph); n != INVALID; ++n) {
523 for (ArcIt a(_graph); a != INVALID; ++a) {
528 std::vector<Node> queue(_node_num);
529 int qfirst = 0, qlast = 0, qsep = 0;
532 typename Digraph::template NodeMap<bool> reached(_graph, false);
534 reached.set(_source, true);
536 bool first_set = true;
538 for (NodeIt t(_graph); t != INVALID; ++t) {
539 if (reached[t]) continue;
540 _sets.push_front(std::list<int>());
543 reached.set(t, true);
545 while (qfirst != qlast) {
546 if (qsep == qfirst) {
548 _sets.front().push_front(bucket_num);
549 _dormant[bucket_num] = !first_set;
550 _first[bucket_num] = _last[bucket_num] = INVALID;
554 Node n = queue[qfirst++];
555 addItem(n, bucket_num);
557 for (OutArcIt a(_graph, n); a != INVALID; ++a) {
558 Node u = _graph.target(a);
559 if (!reached[u] && _tolerance.positive((*_capacity)[a])) {
560 reached.set(u, true);
569 _bucket->set(_source, 0);
572 _source_set->set(_source, true);
574 Node target = _last[_sets.back().back()];
576 for (InArcIt a(_graph, _source); a != INVALID; ++a) {
577 if (_tolerance.positive((*_capacity)[a])) {
578 Node u = _graph.source(a);
579 _flow->set(a, (*_capacity)[a]);
580 _excess->set(u, (*_excess)[u] + (*_capacity)[a]);
581 if (!(*_active)[u] && u != _source) {
586 if ((*_active)[target]) {
590 _highest = _sets.back().begin();
591 while (_highest != _sets.back().end() &&
592 !(*_active)[_first[*_highest]]) {
599 while (_highest != _sets.back().end()) {
600 Node n = _first[*_highest];
601 Value excess = (*_excess)[n];
602 int next_bucket = _node_num;
605 if (++std::list<int>::iterator(_highest) == _sets.back().end()) {
608 under_bucket = *(++std::list<int>::iterator(_highest));
611 for (InArcIt a(_graph, n); a != INVALID; ++a) {
612 Node v = _graph.source(a);
613 if (_dormant[(*_bucket)[v]]) continue;
614 Value rem = (*_capacity)[a] - (*_flow)[a];
615 if (!_tolerance.positive(rem)) continue;
616 if ((*_bucket)[v] == under_bucket) {
617 if (!(*_active)[v] && v != target) {
620 if (!_tolerance.less(rem, excess)) {
621 _flow->set(a, (*_flow)[a] + excess);
622 _excess->set(v, (*_excess)[v] + excess);
627 _excess->set(v, (*_excess)[v] + rem);
628 _flow->set(a, (*_capacity)[a]);
630 } else if (next_bucket > (*_bucket)[v]) {
631 next_bucket = (*_bucket)[v];
635 for (OutArcIt a(_graph, n); a != INVALID; ++a) {
636 Node v = _graph.target(a);
637 if (_dormant[(*_bucket)[v]]) continue;
638 Value rem = (*_flow)[a];
639 if (!_tolerance.positive(rem)) continue;
640 if ((*_bucket)[v] == under_bucket) {
641 if (!(*_active)[v] && v != target) {
644 if (!_tolerance.less(rem, excess)) {
645 _flow->set(a, (*_flow)[a] - excess);
646 _excess->set(v, (*_excess)[v] + excess);
651 _excess->set(v, (*_excess)[v] + rem);
654 } else if (next_bucket > (*_bucket)[v]) {
655 next_bucket = (*_bucket)[v];
661 _excess->set(n, excess);
664 if ((*_next)[n] == INVALID) {
665 typename std::list<std::list<int> >::iterator new_set =
666 _sets.insert(--_sets.end(), std::list<int>());
667 new_set->splice(new_set->end(), _sets.back(),
668 _sets.back().begin(), ++_highest);
669 for (std::list<int>::iterator it = new_set->begin();
670 it != new_set->end(); ++it) {
671 _dormant[*it] = true;
673 while (_highest != _sets.back().end() &&
674 !(*_active)[_first[*_highest]]) {
677 } else if (next_bucket == _node_num) {
678 _first[(*_bucket)[n]] = (*_next)[n];
679 _prev->set((*_next)[n], INVALID);
681 std::list<std::list<int> >::iterator new_set =
682 _sets.insert(--_sets.end(), std::list<int>());
684 new_set->push_front(bucket_num);
685 _bucket->set(n, bucket_num);
686 _first[bucket_num] = _last[bucket_num] = n;
687 _next->set(n, INVALID);
688 _prev->set(n, INVALID);
689 _dormant[bucket_num] = true;
692 while (_highest != _sets.back().end() &&
693 !(*_active)[_first[*_highest]]) {
697 _first[*_highest] = (*_next)[n];
698 _prev->set((*_next)[n], INVALID);
700 while (next_bucket != *_highest) {
703 if (_highest == _sets.back().begin()) {
704 _sets.back().push_front(bucket_num);
705 _dormant[bucket_num] = false;
706 _first[bucket_num] = _last[bucket_num] = INVALID;
711 _bucket->set(n, *_highest);
712 _next->set(n, _first[*_highest]);
713 if (_first[*_highest] != INVALID) {
714 _prev->set(_first[*_highest], n);
716 _last[*_highest] = n;
718 _first[*_highest] = n;
723 if (!(*_active)[_first[*_highest]]) {
725 if (_highest != _sets.back().end() &&
726 !(*_active)[_first[*_highest]]) {
727 _highest = _sets.back().end();
733 if ((*_excess)[target] < _min_cut) {
734 _min_cut = (*_excess)[target];
735 for (NodeIt i(_graph); i != INVALID; ++i) {
736 _min_cut_map->set(i, false);
738 for (std::list<int>::iterator it = _sets.back().begin();
739 it != _sets.back().end(); ++it) {
740 Node n = _first[*it];
741 while (n != INVALID) {
742 _min_cut_map->set(n, true);
750 if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) {
751 if ((*_next)[target] == INVALID) {
752 _last[(*_bucket)[target]] = (*_prev)[target];
753 new_target = (*_prev)[target];
755 _prev->set((*_next)[target], (*_prev)[target]);
756 new_target = (*_next)[target];
758 if ((*_prev)[target] == INVALID) {
759 _first[(*_bucket)[target]] = (*_next)[target];
761 _next->set((*_prev)[target], (*_next)[target]);
764 _sets.back().pop_back();
765 if (_sets.back().empty()) {
769 for (std::list<int>::iterator it = _sets.back().begin();
770 it != _sets.back().end(); ++it) {
771 _dormant[*it] = false;
774 new_target = _last[_sets.back().back()];
777 _bucket->set(target, 0);
779 _source_set->set(target, true);
780 for (InArcIt a(_graph, target); a != INVALID; ++a) {
781 Value rem = (*_capacity)[a] - (*_flow)[a];
782 if (!_tolerance.positive(rem)) continue;
783 Node v = _graph.source(a);
784 if (!(*_active)[v] && !(*_source_set)[v]) {
787 _excess->set(v, (*_excess)[v] + rem);
788 _flow->set(a, (*_capacity)[a]);
791 for (OutArcIt a(_graph, target); a != INVALID; ++a) {
792 Value rem = (*_flow)[a];
793 if (!_tolerance.positive(rem)) continue;
794 Node v = _graph.target(a);
795 if (!(*_active)[v] && !(*_source_set)[v]) {
798 _excess->set(v, (*_excess)[v] + rem);
803 if ((*_active)[target]) {
807 _highest = _sets.back().begin();
808 while (_highest != _sets.back().end() &&
809 !(*_active)[_first[*_highest]]) {
818 /// \name Execution control
819 /// The simplest way to execute the algorithm is to use
820 /// one of the member functions called \ref run().
822 /// If you need more control on the execution,
823 /// first you must call \ref init(), then the \ref calculateIn() or
824 /// \ref calculateOut() functions.
828 /// \brief Initializes the internal data structures.
830 /// Initializes the internal data structures. It creates
831 /// the maps, residual graph adaptors and some bucket structures
832 /// for the algorithm.
834 init(NodeIt(_graph));
837 /// \brief Initializes the internal data structures.
839 /// Initializes the internal data structures. It creates
840 /// the maps, residual graph adaptor and some bucket structures
841 /// for the algorithm. Node \c source is used as the push-relabel
842 /// algorithm's source.
843 void init(const Node& source) {
846 _node_num = countNodes(_graph);
848 _first.resize(_node_num);
849 _last.resize(_node_num);
851 _dormant.resize(_node_num);
854 _flow = new FlowMap(_graph);
857 _next = new typename Digraph::template NodeMap<Node>(_graph);
860 _prev = new typename Digraph::template NodeMap<Node>(_graph);
863 _active = new typename Digraph::template NodeMap<bool>(_graph);
866 _bucket = new typename Digraph::template NodeMap<int>(_graph);
869 _excess = new ExcessMap(_graph);
872 _source_set = new SourceSetMap(_graph);
875 _min_cut_map = new MinCutMap(_graph);
878 _min_cut = std::numeric_limits<Value>::max();
882 /// \brief Calculates a minimum cut with \f$ source \f$ on the
885 /// Calculates a minimum cut with \f$ source \f$ on the
886 /// source-side (i.e. a set \f$ X\subsetneq V \f$ with
887 /// \f$ source \in X \f$ and minimal out-degree).
888 void calculateOut() {
892 /// \brief Calculates a minimum cut with \f$ source \f$ on the
895 /// Calculates a minimum cut with \f$ source \f$ on the
896 /// target-side (i.e. a set \f$ X\subsetneq V \f$ with
897 /// \f$ source \in X \f$ and minimal out-degree).
903 /// \brief Runs the algorithm.
905 /// Runs the algorithm. It finds nodes \c source and \c target
906 /// arbitrarily and then calls \ref init(), \ref calculateOut()
907 /// and \ref calculateIn().
914 /// \brief Runs the algorithm.
916 /// Runs the algorithm. It uses the given \c source node, finds a
917 /// proper \c target and then calls the \ref init(), \ref
918 /// calculateOut() and \ref calculateIn().
919 void run(const Node& s) {
927 /// \name Query Functions
928 /// The result of the %HaoOrlin algorithm
929 /// can be obtained using these functions.
931 /// Before using these functions, either \ref run(), \ref
932 /// calculateOut() or \ref calculateIn() must be called.
936 /// \brief Returns the value of the minimum value cut.
938 /// Returns the value of the minimum value cut.
939 Value minCutValue() const {
944 /// \brief Returns a minimum cut.
946 /// Sets \c nodeMap to the characteristic vector of a minimum
947 /// value cut: it will give a nonempty set \f$ X\subsetneq V \f$
948 /// with minimal out-degree (i.e. \c nodeMap will be true exactly
949 /// for the nodes of \f$ X \f$). \pre nodeMap should be a
950 /// bool-valued node-map.
951 template <typename NodeMap>
952 Value minCutMap(NodeMap& nodeMap) const {
953 for (NodeIt it(_graph); it != INVALID; ++it) {
954 nodeMap.set(it, (*_min_cut_map)[it]);
966 #endif //LEMON_HAO_ORLIN_H