1 /* -*- C++ -*- |
1 /* -*- C++ -*- |
2 * lemon/minimal_cut.h - Part of LEMON, a generic C++ optimization library |
2 * lemon/minimum_cut.h - Part of LEMON, a generic C++ optimization library |
3 * |
3 * |
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
5 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
5 * (Egervary Research Group on Combinatorial Optimization, EGRES). |
6 * |
6 * |
7 * Permission to use, modify and distribute this software is granted |
7 * Permission to use, modify and distribute this software is granted |
12 * express or implied, and with no claim as to its suitability for any |
12 * express or implied, and with no claim as to its suitability for any |
13 * purpose. |
13 * purpose. |
14 * |
14 * |
15 */ |
15 */ |
16 |
16 |
17 #ifndef LEMON_MINIMAL_CUT_H |
17 #ifndef LEMON_MINIMUM_CUT_H |
18 #define LEMON_MINIMAL_CUT_H |
18 #define LEMON_MINIMUM_CUT_H |
19 |
19 |
20 |
20 |
21 /// \ingroup topology |
21 /// \ingroup topology |
22 /// \file |
22 /// \file |
23 /// \brief Maximum cardinality search and minimal cut in undirected graphs. |
23 /// \brief Maximum cardinality search and minimum cut in undirected graphs. |
24 |
24 |
25 #include <lemon/list_graph.h> |
25 #include <lemon/list_graph.h> |
26 #include <lemon/bin_heap.h> |
26 #include <lemon/bin_heap.h> |
27 #include <lemon/linear_heap.h> |
27 #include <lemon/linear_heap.h> |
28 |
28 |
95 /// the \ref BinHeap, but it is specialized when the |
95 /// the \ref BinHeap, but it is specialized when the |
96 /// CapacityMap is ConstMap<Graph::Node, Const<int, 1> > |
96 /// CapacityMap is ConstMap<Graph::Node, Const<int, 1> > |
97 /// to LinearHeap. |
97 /// to LinearHeap. |
98 /// |
98 /// |
99 /// \sa MaxCardinalitySearch |
99 /// \sa MaxCardinalitySearch |
100 typedef typename _minimal_cut_bits |
100 typedef typename _minimum_cut_bits |
101 ::HeapSelector<CapacityMap> |
101 ::HeapSelector<CapacityMap> |
102 ::template Selector<typename Graph::Node, Value, HeapCrossRef> |
102 ::template Selector<typename Graph::Node, Value, HeapCrossRef> |
103 ::Heap Heap; |
103 ::Heap Heap; |
104 |
104 |
105 /// \brief Instantiates a Heap. |
105 /// \brief Instantiates a Heap. |
686 bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } |
686 bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } |
687 |
687 |
688 ///@} |
688 ///@} |
689 }; |
689 }; |
690 |
690 |
691 /// \brief Default traits class of MinimalCut class. |
691 /// \brief Default traits class of MinimumCut class. |
692 /// |
692 /// |
693 /// Default traits class of MinimalCut class. |
693 /// Default traits class of MinimumCut class. |
694 /// \param Graph Graph type. |
694 /// \param Graph Graph type. |
695 /// \param CapacityMap Type of length map. |
695 /// \param CapacityMap Type of length map. |
696 template <typename _Graph, typename _CapacityMap> |
696 template <typename _Graph, typename _CapacityMap> |
697 struct MinimalCutDefaultTraits { |
697 struct MinimumCutDefaultTraits { |
698 /// \brief The type of the capacity of the edges. |
698 /// \brief The type of the capacity of the edges. |
699 typedef typename _CapacityMap::Value Value; |
699 typedef typename _CapacityMap::Value Value; |
700 |
700 |
701 /// The graph type the algorithm runs on. |
701 /// The graph type the algorithm runs on. |
702 typedef _Graph Graph; |
702 typedef _Graph Graph; |
754 /// HeapCrossRef. |
754 /// HeapCrossRef. |
755 static HeapCrossRef *createHeapCrossRef(const WorkGraph &graph) { |
755 static HeapCrossRef *createHeapCrossRef(const WorkGraph &graph) { |
756 return new HeapCrossRef(graph); |
756 return new HeapCrossRef(graph); |
757 } |
757 } |
758 |
758 |
759 /// \brief The heap type used by MinimalCut algorithm. |
759 /// \brief The heap type used by MinimumCut algorithm. |
760 /// |
760 /// |
761 /// The heap type used by MinimalCut algorithm. It should |
761 /// The heap type used by MinimumCut algorithm. It should |
762 /// maximalize the priorities and the heap's key type is |
762 /// maximalize the priorities and the heap's key type is |
763 /// the work graph's node. |
763 /// the work graph's node. |
764 /// |
764 /// |
765 /// \sa BinHeap |
765 /// \sa BinHeap |
766 /// \sa MinimalCut |
766 /// \sa MinimumCut |
767 typedef typename _minimal_cut_bits |
767 typedef typename _minimum_cut_bits |
768 ::HeapSelector<CapacityMap> |
768 ::HeapSelector<CapacityMap> |
769 ::template Selector<typename WorkGraph::Node, Value, HeapCrossRef> |
769 ::template Selector<typename WorkGraph::Node, Value, HeapCrossRef> |
770 ::Heap Heap; |
770 ::Heap Heap; |
771 |
771 |
772 /// \brief Instantiates a Heap. |
772 /// \brief Instantiates a Heap. |
828 }; |
828 }; |
829 } |
829 } |
830 |
830 |
831 /// \ingroup topology |
831 /// \ingroup topology |
832 /// |
832 /// |
833 /// \brief Calculates the minimal cut in an undirected graph. |
833 /// \brief Calculates the minimum cut in an undirected graph. |
834 /// |
834 /// |
835 /// Calculates the minimal cut in an undirected graph. |
835 /// Calculates the minimum cut in an undirected graph. |
836 /// The algorithm separates the graph's nodes to two partitions with the |
836 /// The algorithm separates the graph's nodes to two partitions with the |
837 /// minimal sum of edge capacities between the two partitions. The |
837 /// minimum sum of edge capacities between the two partitions. The |
838 /// algorithm can be used to test the network reliability specifically |
838 /// algorithm can be used to test the network reliability specifically |
839 /// to test how many links have to be destroyed in the network to split it |
839 /// to test how many links have to be destroyed in the network to split it |
840 /// at least two distinict subnetwork. |
840 /// at least two distinict subnetwork. |
841 /// |
841 /// |
842 /// The complexity of the algorithm is O(n*e*log(n)) but with Fibonacci |
842 /// The complexity of the algorithm is O(n*e*log(n)) but with Fibonacci |
845 #ifdef DOXYGEN |
845 #ifdef DOXYGEN |
846 template <typename _Graph, typename _CapacityMap, typename _Traits> |
846 template <typename _Graph, typename _CapacityMap, typename _Traits> |
847 #else |
847 #else |
848 template <typename _Graph = ListUGraph, |
848 template <typename _Graph = ListUGraph, |
849 typename _CapacityMap = typename _Graph::template UEdgeMap<int>, |
849 typename _CapacityMap = typename _Graph::template UEdgeMap<int>, |
850 typename _Traits = MinimalCutDefaultTraits<_Graph, _CapacityMap> > |
850 typename _Traits = MinimumCutDefaultTraits<_Graph, _CapacityMap> > |
851 #endif |
851 #endif |
852 class MinimalCut { |
852 class MinimumCut { |
853 public: |
853 public: |
854 /// \brief \ref Exception for uninitialized parameters. |
854 /// \brief \ref Exception for uninitialized parameters. |
855 /// |
855 /// |
856 /// This error represents problems in the initialization |
856 /// This error represents problems in the initialization |
857 /// of the parameters of the algorithms. |
857 /// of the parameters of the algorithms. |
858 class UninitializedParameter : public lemon::UninitializedParameter { |
858 class UninitializedParameter : public lemon::UninitializedParameter { |
859 public: |
859 public: |
860 virtual const char* exceptionName() const { |
860 virtual const char* exceptionName() const { |
861 return "lemon::MinimalCut::UninitializedParameter"; |
861 return "lemon::MinimumCut::UninitializedParameter"; |
862 } |
862 } |
863 }; |
863 }; |
864 |
864 |
865 |
865 |
866 private: |
866 private: |
902 /// the capacity type to constMap<UEdge, int, 1>() |
902 /// the capacity type to constMap<UEdge, int, 1>() |
903 /// |
903 /// |
904 /// \ref named-templ-param "Named parameter" for setting |
904 /// \ref named-templ-param "Named parameter" for setting |
905 /// the capacity type to constMap<UEdge, int, 1>() |
905 /// the capacity type to constMap<UEdge, int, 1>() |
906 struct DefNeutralCapacity |
906 struct DefNeutralCapacity |
907 : public MinimalCut<Graph, CapacityMap, DefNeutralCapacityTraits> { |
907 : public MinimumCut<Graph, CapacityMap, DefNeutralCapacityTraits> { |
908 typedef MinimalCut<Graph, CapacityMap, DefNeutralCapacityTraits> Create; |
908 typedef MinimumCut<Graph, CapacityMap, DefNeutralCapacityTraits> Create; |
909 }; |
909 }; |
910 |
910 |
911 |
911 |
912 template <class H, class CR> |
912 template <class H, class CR> |
913 struct DefHeapTraits : public Traits { |
913 struct DefHeapTraits : public Traits { |
925 /// |
925 /// |
926 /// \ref named-templ-param "Named parameter" for setting heap and cross |
926 /// \ref named-templ-param "Named parameter" for setting heap and cross |
927 /// reference type |
927 /// reference type |
928 template <class H, class CR = typename Graph::template NodeMap<int> > |
928 template <class H, class CR = typename Graph::template NodeMap<int> > |
929 struct DefHeap |
929 struct DefHeap |
930 : public MinimalCut<Graph, CapacityMap, DefHeapTraits<H, CR> > { |
930 : public MinimumCut<Graph, CapacityMap, DefHeapTraits<H, CR> > { |
931 typedef MinimalCut< Graph, CapacityMap, DefHeapTraits<H, CR> > Create; |
931 typedef MinimumCut< Graph, CapacityMap, DefHeapTraits<H, CR> > Create; |
932 }; |
932 }; |
933 |
933 |
934 template <class H, class CR> |
934 template <class H, class CR> |
935 struct DefStandardHeapTraits : public Traits { |
935 struct DefStandardHeapTraits : public Traits { |
936 typedef CR HeapCrossRef; |
936 typedef CR HeapCrossRef; |
950 /// reference type. It can allocate the heap and the cross reference |
950 /// reference type. It can allocate the heap and the cross reference |
951 /// object if the cross reference's constructor waits for the graph as |
951 /// object if the cross reference's constructor waits for the graph as |
952 /// parameter and the heap's constructor waits for the cross reference. |
952 /// parameter and the heap's constructor waits for the cross reference. |
953 template <class H, class CR = typename Graph::template NodeMap<int> > |
953 template <class H, class CR = typename Graph::template NodeMap<int> > |
954 struct DefStandardHeap |
954 struct DefStandardHeap |
955 : public MinimalCut<Graph, CapacityMap, DefStandardHeapTraits<H, CR> > { |
955 : public MinimumCut<Graph, CapacityMap, DefStandardHeapTraits<H, CR> > { |
956 typedef MinimalCut<Graph, CapacityMap, DefStandardHeapTraits<H, CR> > |
956 typedef MinimumCut<Graph, CapacityMap, DefStandardHeapTraits<H, CR> > |
957 Create; |
957 Create; |
958 }; |
958 }; |
959 |
959 |
960 ///@} |
960 ///@} |
961 |
961 |
987 /// Pointer to the heap. |
987 /// Pointer to the heap. |
988 Heap *_heap; |
988 Heap *_heap; |
989 /// Indicates if \ref _heap is locally allocated (\c true) or not. |
989 /// Indicates if \ref _heap is locally allocated (\c true) or not. |
990 bool local_heap; |
990 bool local_heap; |
991 |
991 |
992 /// The minimal cut value. |
992 /// The minimum cut value. |
993 Value _minimal_cut; |
993 Value _minimum_cut; |
994 /// The number of the nodes of the work graph. |
994 /// The number of the nodes of the work graph. |
995 int _node_num; |
995 int _node_num; |
996 /// The first and last node of the min cut in the next list; |
996 /// The first and last node of the min cut in the next list; |
997 typename Graph::Node _first_node, _last_node; |
997 typename Graph::Node _first_node, _last_node; |
998 |
998 |
1050 } |
1050 } |
1051 } |
1051 } |
1052 |
1052 |
1053 public : |
1053 public : |
1054 |
1054 |
1055 typedef MinimalCut Create; |
1055 typedef MinimumCut Create; |
1056 |
1056 |
1057 |
1057 |
1058 /// \brief Constructor. |
1058 /// \brief Constructor. |
1059 /// |
1059 /// |
1060 ///\param graph the graph the algorithm will run on. |
1060 ///\param graph the graph the algorithm will run on. |
1061 ///\param capacity the capacity map used by the algorithm. |
1061 ///\param capacity the capacity map used by the algorithm. |
1062 MinimalCut(const Graph& graph, const CapacityMap& capacity) |
1062 MinimumCut(const Graph& graph, const CapacityMap& capacity) |
1063 : _graph(&graph), |
1063 : _graph(&graph), |
1064 _capacity(&capacity), local_capacity(false), |
1064 _capacity(&capacity), local_capacity(false), |
1065 _work_graph(0), local_work_graph(false), |
1065 _work_graph(0), local_work_graph(false), |
1066 _work_capacity(0), local_work_capacity(false), |
1066 _work_capacity(0), local_work_capacity(false), |
1067 _heap_cross_ref(0), local_heap_cross_ref(false), |
1067 _heap_cross_ref(0), local_heap_cross_ref(false), |
1074 /// defines how can we instantiate a local capacity map. |
1074 /// defines how can we instantiate a local capacity map. |
1075 /// If the DefNeutralCapacity used the algorithm automatically |
1075 /// If the DefNeutralCapacity used the algorithm automatically |
1076 /// construct the capacity map. |
1076 /// construct the capacity map. |
1077 /// |
1077 /// |
1078 ///\param graph the graph the algorithm will run on. |
1078 ///\param graph the graph the algorithm will run on. |
1079 MinimalCut(const Graph& graph) |
1079 MinimumCut(const Graph& graph) |
1080 : _graph(&graph), |
1080 : _graph(&graph), |
1081 _capacity(0), local_capacity(false), |
1081 _capacity(0), local_capacity(false), |
1082 _work_graph(0), local_work_graph(false), |
1082 _work_graph(0), local_work_graph(false), |
1083 _work_capacity(0), local_work_capacity(false), |
1083 _work_capacity(0), local_work_capacity(false), |
1084 _heap_cross_ref(0), local_heap_cross_ref(false), |
1084 _heap_cross_ref(0), local_heap_cross_ref(false), |
1086 _first(0), _last(0), _next(0) {} |
1086 _first(0), _last(0), _next(0) {} |
1087 |
1087 |
1088 /// \brief Destructor. |
1088 /// \brief Destructor. |
1089 /// |
1089 /// |
1090 /// Destructor. |
1090 /// Destructor. |
1091 ~MinimalCut() { |
1091 ~MinimumCut() { |
1092 if (local_heap) delete _heap; |
1092 if (local_heap) delete _heap; |
1093 if (local_heap_cross_ref) delete _heap_cross_ref; |
1093 if (local_heap_cross_ref) delete _heap_cross_ref; |
1094 if (_first) delete _first; |
1094 if (_first) delete _first; |
1095 if (_last) delete _last; |
1095 if (_last) delete _last; |
1096 if (_next) delete _next; |
1096 if (_next) delete _next; |
1104 /// Sets the heap and the cross reference used by algorithm. |
1104 /// Sets the heap and the cross reference used by algorithm. |
1105 /// If you don't use this function before calling \ref run(), |
1105 /// If you don't use this function before calling \ref run(), |
1106 /// it will allocate one. The destuctor deallocates this |
1106 /// it will allocate one. The destuctor deallocates this |
1107 /// automatically allocated heap and cross reference, of course. |
1107 /// automatically allocated heap and cross reference, of course. |
1108 /// \return <tt> (*this) </tt> |
1108 /// \return <tt> (*this) </tt> |
1109 MinimalCut &heap(Heap& heap, HeapCrossRef &crossRef) |
1109 MinimumCut &heap(Heap& heap, HeapCrossRef &crossRef) |
1110 { |
1110 { |
1111 if (local_heap_cross_ref) { |
1111 if (local_heap_cross_ref) { |
1112 delete _heap_cross_ref; |
1112 delete _heap_cross_ref; |
1113 local_heap_cross_ref=false; |
1113 local_heap_cross_ref=false; |
1114 } |
1114 } |
1126 /// Sets the work graph used by algorithm. |
1126 /// Sets the work graph used by algorithm. |
1127 /// If you don't use this function before calling \ref run(), |
1127 /// If you don't use this function before calling \ref run(), |
1128 /// it will allocate one. The destuctor deallocates this |
1128 /// it will allocate one. The destuctor deallocates this |
1129 /// automatically allocated graph, of course. |
1129 /// automatically allocated graph, of course. |
1130 /// \return <tt> (*this) </tt> |
1130 /// \return <tt> (*this) </tt> |
1131 MinimalCut &workGraph(WorkGraph& work_graph) |
1131 MinimumCut &workGraph(WorkGraph& work_graph) |
1132 { |
1132 { |
1133 if(local_work_graph) { |
1133 if(local_work_graph) { |
1134 delete _work_graph; |
1134 delete _work_graph; |
1135 local_work_graph=false; |
1135 local_work_graph=false; |
1136 } |
1136 } |
1143 /// Sets the work capacity map used by algorithm. |
1143 /// Sets the work capacity map used by algorithm. |
1144 /// If you don't use this function before calling \ref run(), |
1144 /// If you don't use this function before calling \ref run(), |
1145 /// it will allocate one. The destuctor deallocates this |
1145 /// it will allocate one. The destuctor deallocates this |
1146 /// automatically allocated graph, of course. |
1146 /// automatically allocated graph, of course. |
1147 /// \return <tt> (*this) </tt> |
1147 /// \return <tt> (*this) </tt> |
1148 MinimalCut &workCapacityMap(WorkCapacityMap& work_capacity_map) |
1148 MinimumCut &workCapacityMap(WorkCapacityMap& work_capacity_map) |
1149 { |
1149 { |
1150 if(local_work_capacity) { |
1150 if(local_work_capacity) { |
1151 delete _work_capacity; |
1151 delete _work_capacity; |
1152 local_work_capacity=false; |
1152 local_work_capacity=false; |
1153 } |
1153 } |
1176 |
1176 |
1177 /// \brief Processes the next phase |
1177 /// \brief Processes the next phase |
1178 /// |
1178 /// |
1179 /// Processes the next phase in the algorithm. The function |
1179 /// Processes the next phase in the algorithm. The function |
1180 /// should be called countNodes(graph) - 1 times to get |
1180 /// should be called countNodes(graph) - 1 times to get |
1181 /// surely the minimal cut in the graph. The |
1181 /// surely the minimum cut in the graph. The |
1182 /// |
1182 /// |
1183 ///\return %True when the algorithm finished. |
1183 ///\return %True when the algorithm finished. |
1184 bool processNextPhase() { |
1184 bool processNextPhase() { |
1185 if (_node_num <= 1) return true; |
1185 if (_node_num <= 1) return true; |
1186 using namespace _minimal_cut_bits; |
1186 using namespace _minimum_cut_bits; |
1187 |
1187 |
1188 typedef typename WorkGraph::Node Node; |
1188 typedef typename WorkGraph::Node Node; |
1189 typedef typename WorkGraph::NodeIt NodeIt; |
1189 typedef typename WorkGraph::NodeIt NodeIt; |
1190 typedef typename WorkGraph::UEdge UEdge; |
1190 typedef typename WorkGraph::UEdge UEdge; |
1191 typedef typename WorkGraph::IncEdgeIt IncEdgeIt; |
1191 typedef typename WorkGraph::IncEdgeIt IncEdgeIt; |
1232 } else { |
1232 } else { |
1233 (*_work_capacity)[edges[node]] += (*_work_capacity)[it]; |
1233 (*_work_capacity)[edges[node]] += (*_work_capacity)[it]; |
1234 } |
1234 } |
1235 } |
1235 } |
1236 |
1236 |
1237 if (_first_node == INVALID || current_cut < _minimal_cut) { |
1237 if (_first_node == INVALID || current_cut < _minimum_cut) { |
1238 _first_node = (*_first)[first_node]; |
1238 _first_node = (*_first)[first_node]; |
1239 _last_node = (*_last)[first_node]; |
1239 _last_node = (*_last)[first_node]; |
1240 _minimal_cut = current_cut; |
1240 _minimum_cut = current_cut; |
1241 } |
1241 } |
1242 |
1242 |
1243 _work_graph->erase(first_node); |
1243 _work_graph->erase(first_node); |
1244 |
1244 |
1245 for (IncEdgeIt it(*_work_graph, second_node); it != INVALID; ++it) { |
1245 for (IncEdgeIt it(*_work_graph, second_node); it != INVALID; ++it) { |
1282 } |
1282 } |
1283 |
1283 |
1284 ///@} |
1284 ///@} |
1285 |
1285 |
1286 /// \name Query Functions |
1286 /// \name Query Functions |
1287 /// The result of the %MinimalCut algorithm can be obtained using these |
1287 /// The result of the %MinimumCut algorithm can be obtained using these |
1288 /// functions.\n |
1288 /// functions.\n |
1289 /// Before the use of these functions, |
1289 /// Before the use of these functions, |
1290 /// either run() or start() must be called. |
1290 /// either run() or start() must be called. |
1291 |
1291 |
1292 ///@{ |
1292 ///@{ |
1293 |
1293 |
1294 /// \brief Returns the minimal cut value. |
1294 /// \brief Returns the minimum cut value. |
1295 /// |
1295 /// |
1296 /// Returns the minimal cut value if the algorithm finished. |
1296 /// Returns the minimum cut value if the algorithm finished. |
1297 /// After the first processNextPhase() it is a value of a |
1297 /// After the first processNextPhase() it is a value of a |
1298 /// valid cut in the graph. |
1298 /// valid cut in the graph. |
1299 Value minCut() const { |
1299 Value minCut() const { |
1300 return _minimal_cut; |
1300 return _minimum_cut; |
1301 } |
1301 } |
1302 |
1302 |
1303 /// \brief Returns a minimal cut in a NodeMap. |
1303 /// \brief Returns a minimum cut in a NodeMap. |
1304 /// |
1304 /// |
1305 /// It sets the nodes of one of the two partitions to true in |
1305 /// It sets the nodes of one of the two partitions to true in |
1306 /// the given BoolNodeMap. The map contains a valid cut if the |
1306 /// the given BoolNodeMap. The map contains a valid cut if the |
1307 /// map have been setted false previously. |
1307 /// map have been setted false previously. |
1308 template <typename NodeMap> |
1308 template <typename NodeMap> |
1313 } |
1313 } |
1314 nodeMap.set(_last_node, true); |
1314 nodeMap.set(_last_node, true); |
1315 return minCut(); |
1315 return minCut(); |
1316 } |
1316 } |
1317 |
1317 |
1318 /// \brief Returns a minimal cut in a NodeMap. |
1318 /// \brief Returns a minimum cut in a NodeMap. |
1319 /// |
1319 /// |
1320 /// It sets the nodes of one of the two partitions to true and |
1320 /// It sets the nodes of one of the two partitions to true and |
1321 /// the other partition to false. The function first set all of the |
1321 /// the other partition to false. The function first set all of the |
1322 /// nodes to false and after it call the quickMinCut() member. |
1322 /// nodes to false and after it call the quickMinCut() member. |
1323 template <typename NodeMap> |
1323 template <typename NodeMap> |
1327 } |
1327 } |
1328 quickMinCut(nodeMap); |
1328 quickMinCut(nodeMap); |
1329 return minCut(); |
1329 return minCut(); |
1330 } |
1330 } |
1331 |
1331 |
1332 /// \brief Returns a minimal cut in an EdgeMap. |
1332 /// \brief Returns a minimum cut in an EdgeMap. |
1333 /// |
1333 /// |
1334 /// If an undirected edge is cut edge then it will be |
1334 /// If an undirected edge is cut edge then it will be |
1335 /// setted to true and the others will be setted to false in the given map. |
1335 /// setted to true and the others will be setted to false in the given map. |
1336 template <typename EdgeMap> |
1336 template <typename EdgeMap> |
1337 Value cutEdges(EdgeMap& edgeMap) const { |
1337 Value cutEdges(EdgeMap& edgeMap) const { |