jacint@620: // -*- C++ -*- jacint@620: #ifndef HUGO_MAX_FLOW_H jacint@620: #define HUGO_MAX_FLOW_H jacint@620: jacint@620: ///\ingroup galgs jacint@620: ///\file jacint@620: ///\brief Maximum flow algorithm. jacint@620: jacint@620: #define H0 20 jacint@620: #define H1 1 jacint@620: jacint@620: #include jacint@620: #include jacint@620: #include jacint@620: jacint@620: #include jacint@620: #include jacint@620: #include jacint@620: #include jacint@620: #include jacint@620: jacint@620: /// \file jacint@620: /// \brief Dimacs file format reader. jacint@620: jacint@620: namespace hugo { jacint@620: jacint@620: /// \addtogroup galgs jacint@620: /// @{ jacint@620: jacint@620: ///Maximum flow algorithms class. jacint@620: jacint@620: ///This class provides various algorithms for finding a flow of jacint@620: ///maximum value in a directed graph. The \e source node, the \e jacint@620: ///target node, the \e capacity of the edges and the \e starting \e jacint@620: ///flow value of the edges can be passed to the algorithm by the jacint@620: ///constructor. It is possible to change these quantities using the jacint@620: ///functions \ref resetSource, \ref resetTarget, \ref resetCap and jacint@620: ///\ref resetFlow. Before any subsequent runs of any algorithm of jacint@620: ///the class \ref resetFlow should be called, otherwise it will jacint@620: ///start from a maximum flow. jacint@620: jacint@620: ///After running an algorithm of the class, the maximum value of a jacint@620: ///value can be obtained by calling \ref flowValue(). The minimum jacint@620: ///value cut can be written into a \c node map of \c bools by jacint@620: ///calling \ref minCut. (\ref minMinCut and \ref maxMinCut writes jacint@620: ///the inclusionwise minimum and maximum of the minimum value jacint@620: ///cuts, resp.) jacint@620: jacint@620: ///\param Graph The undirected graph type the algorithm runs on. jacint@620: ///\param Num The number type of the capacities and the flow values. jacint@620: ///\param The type of the capacity map. jacint@620: ///\param The type of the flow map. jacint@620: jacint@620: ///\author Marton Makai, Jacint Szabo jacint@620: template , jacint@620: typename FlowMap=typename Graph::template EdgeMap > jacint@620: class MaxFlow { jacint@620: jacint@620: typedef typename Graph::Node Node; jacint@620: typedef typename Graph::NodeIt NodeIt; jacint@620: typedef typename Graph::OutEdgeIt OutEdgeIt; jacint@620: typedef typename Graph::InEdgeIt InEdgeIt; jacint@620: jacint@620: typedef typename std::vector > VecStack; jacint@620: typedef typename Graph::template NodeMap NNMap; jacint@620: typedef typename std::vector VecNode; jacint@620: jacint@620: typedef ResGraphWrapper ResGW; jacint@620: typedef typename ResGW::OutEdgeIt ResGWOutEdgeIt; jacint@620: typedef typename ResGW::Edge ResGWEdge; jacint@620: //typedef typename ResGW::template NodeMap ReachedMap; //fixme jacint@620: typedef typename Graph::template NodeMap ReachedMap; jacint@620: jacint@620: const Graph* g; jacint@620: Node s; jacint@620: Node t; jacint@620: const CapMap* capacity; jacint@620: FlowMap* flow; jacint@620: int n; //the number of nodes of G jacint@620: jacint@620: //level works as a bool map in augmenting path algorithms and is jacint@620: //used by bfs for storing reached information. In preflow, it jacint@620: //shows the levels of nodes. jacint@620: ReachedMap level; jacint@620: jacint@620: //excess is needed only in preflow jacint@620: typename Graph::template NodeMap excess; jacint@620: jacint@620: jacint@620: //fixme jacint@620: // protected: jacint@620: // MaxFlow() { } jacint@620: // void set(const Graph& _G, Node _s, Node _t, const CapMap& _capacity, jacint@620: // FlowMap& _flow) jacint@620: // { jacint@620: // g=&_G; jacint@620: // s=_s; jacint@620: // t=_t; jacint@620: // capacity=&_capacity; jacint@620: // flow=&_flow; jacint@620: // n=_G.nodeNum; jacint@620: // level.set (_G); //kellene vmi ilyesmi fv jacint@620: // excess(_G,0); //itt is jacint@620: // } jacint@620: jacint@620: public: jacint@620: jacint@620: ///Indicates the property of the starting flow. jacint@620: jacint@620: ///Indicates the property of the starting flow. The meanings: jacint@620: ///- \c ZERO_FLOW: constant zero flow jacint@620: ///- \c GEN_FLOW: any flow, i.e. the sum of the in-flows equals to jacint@620: ///the sum of the out-flows in every node except the source and jacint@620: ///the target. jacint@620: ///- \c PRE_FLOW: any preflow, i.e. the sum of the in-flows is at jacint@620: ///least the sum of the out-flows in every node except the source. jacint@620: enum flowEnum{ jacint@620: ZERO_FLOW=0, jacint@620: GEN_FLOW=1, jacint@620: PRE_FLOW=2 jacint@620: }; jacint@620: jacint@620: MaxFlow(const Graph& _G, Node _s, Node _t, const CapMap& _capacity, jacint@620: FlowMap& _flow) : jacint@620: g(&_G), s(_s), t(_t), capacity(&_capacity), jacint@620: flow(&_flow), n(_G.nodeNum()), level(_G), excess(_G,0) {} jacint@620: jacint@620: ///Runs a maximum flow algorithm. jacint@620: jacint@620: ///Runs a preflow algorithm, which is the fastest maximum flow jacint@620: ///algorithm up-to-date. The default for \c fe is ZERO_FLOW. jacint@620: ///\pre The starting flow must be a jacint@620: /// - constant zero flow if \c fe is \c ZERO_FLOW, jacint@620: /// - an arbitary flow if \c fe is \c GEN_FLOW, jacint@620: /// - an arbitary preflow if \c fe is \c PRE_FLOW. jacint@620: void run( flowEnum fe=ZERO_FLOW ) { jacint@620: preflow(fe); jacint@620: } jacint@620: jacint@620: ///Runs a preflow algorithm. jacint@620: jacint@620: ///Runs a preflow algorithm. The preflow algorithms provide the jacint@620: ///fastest way to compute a maximum flow in a directed graph. jacint@620: ///\pre The starting flow must be a jacint@620: /// - constant zero flow if \c fe is \c ZERO_FLOW, jacint@620: /// - an arbitary flow if \c fe is \c GEN_FLOW, jacint@620: /// - an arbitary preflow if \c fe is \c PRE_FLOW. jacint@620: void preflow(flowEnum fe) { jacint@620: preflowPhase1(fe); jacint@620: preflowPhase2(); jacint@620: } jacint@620: // Heuristics: jacint@620: // 2 phase jacint@620: // gap jacint@620: // list 'level_list' on the nodes on level i implemented by hand jacint@620: // stack 'active' on the active nodes on level i jacint@620: // runs heuristic 'highest label' for H1*n relabels jacint@620: // runs heuristic 'bound decrease' for H0*n relabels, starts with 'highest label' jacint@620: // Parameters H0 and H1 are initialized to 20 and 1. jacint@620: jacint@620: ///Runs the first phase of the preflow algorithm. jacint@620: jacint@620: ///The preflow algorithm consists of two phases, this method runs the jacint@620: ///first phase. After the first phase the maximum flow value and a jacint@620: ///minimum value cut can already be computed, though a maximum flow jacint@620: ///is net yet obtained. So after calling this method \ref flowValue jacint@620: ///and \ref actMinCut gives proper results. jacint@620: ///\warning: \ref minCut, \ref minMinCut and \ref maxMinCut do not jacint@620: ///give minimum value cuts unless calling \ref preflowPhase2. jacint@620: ///\pre The starting flow must be a jacint@620: /// - constant zero flow if \c fe is \c ZERO_FLOW, jacint@620: /// - an arbitary flow if \c fe is \c GEN_FLOW, jacint@620: /// - an arbitary preflow if \c fe is \c PRE_FLOW. jacint@620: void preflowPhase1( flowEnum fe ); jacint@620: jacint@620: ///Runs the second phase of the preflow algorithm. jacint@620: jacint@620: ///The preflow algorithm consists of two phases, this method runs jacint@620: ///the second phase. After calling \ref preflowPhase1 and then jacint@620: ///\ref preflowPhase2 the methods \ref flowValue, \ref minCut, jacint@620: ///\ref minMinCut and \ref maxMinCut give proper results. jacint@620: ///\pre \ref preflowPhase1 must be called before. jacint@620: void preflowPhase2(); jacint@620: jacint@620: /// Starting from a flow, this method searches for an augmenting path jacint@620: /// according to the Edmonds-Karp algorithm jacint@620: /// and augments the flow on if any. jacint@620: /// The return value shows if the augmentation was successful. jacint@620: bool augmentOnShortestPath(); jacint@620: jacint@620: /// Starting from a flow, this method searches for an augmenting blockin jacint@620: /// flow according to Dinits' algorithm and augments the flow on if any. jacint@620: /// The blocking flow is computed in a physically constructed jacint@620: /// residual graph of type \c Mutablegraph. jacint@620: /// The return value show sif the augmentation was succesful. jacint@620: template bool augmentOnBlockingFlow(); jacint@620: jacint@620: /// The same as \c augmentOnBlockingFlow but the jacint@620: /// residual graph is not constructed physically. jacint@620: /// The return value shows if the augmentation was succesful. jacint@620: bool augmentOnBlockingFlow2(); jacint@620: jacint@620: /// Returns the actual flow value. jacint@620: /// More precisely, it returns the negative excess of s, thus jacint@620: /// this works also for preflows. jacint@620: ///Can be called already after \ref preflowPhase1. jacint@620: jacint@620: Num flowValue() { jacint@620: Num a=0; jacint@620: FOR_EACH_INC_LOC(OutEdgeIt, e, *g, s) a+=(*flow)[e]; jacint@620: FOR_EACH_INC_LOC(InEdgeIt, e, *g, s) a-=(*flow)[e]; jacint@620: return a; jacint@620: //marci figyu: excess[t] epp ezt adja preflow 0. fazisa utan jacint@620: } jacint@620: jacint@620: ///Returns a minimum value cut after calling \ref preflowPhase1. jacint@620: jacint@620: ///After the first phase of the preflow algorithm the maximum flow jacint@620: ///value and a minimum value cut can already be computed. This jacint@620: ///method can be called after running \ref preflowPhase1 for jacint@620: ///obtaining a minimum value cut. jacint@620: ///\warning: Gives proper result only right after calling \ref jacint@620: ///preflowPhase1. jacint@620: ///\todo We have to make some status variable which shows the actual state jacint@620: /// of the class. This enables us to determine which methods are valid jacint@620: /// for MinCut computation jacint@620: template jacint@620: void actMinCut(_CutMap& M) { jacint@620: NodeIt v; jacint@620: for(g->first(v); g->valid(v); g->next(v)) { jacint@620: if ( level[v] < n ) { jacint@620: M.set(v,false); jacint@620: } else { jacint@620: M.set(v,true); jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: ///Returns the inclusionwise minimum of the minimum value cuts. jacint@620: jacint@620: ///Sets \c M to the characteristic vector of the minimum value cut jacint@620: ///which is inclusionwise minimum. It is computed by processing jacint@620: ///a bfs from the source node \c s in the residual graph. jacint@620: ///\pre M should be a node map of bools initialized to false. jacint@620: ///\pre \c flow must be a maximum flow. jacint@620: template jacint@620: void minMinCut(_CutMap& M) { jacint@620: jacint@620: std::queue queue; jacint@620: jacint@620: M.set(s,true); jacint@620: queue.push(s); jacint@620: jacint@620: while (!queue.empty()) { jacint@620: Node w=queue.front(); jacint@620: queue.pop(); jacint@620: jacint@620: OutEdgeIt e; jacint@620: for(g->first(e,w) ; g->valid(e); g->next(e)) { jacint@620: Node v=g->head(e); jacint@620: if (!M[v] && (*flow)[e] < (*capacity)[e] ) { jacint@620: queue.push(v); jacint@620: M.set(v, true); jacint@620: } jacint@620: } jacint@620: jacint@620: InEdgeIt f; jacint@620: for(g->first(f,w) ; g->valid(f); g->next(f)) { jacint@620: Node v=g->tail(f); jacint@620: if (!M[v] && (*flow)[f] > 0 ) { jacint@620: queue.push(v); jacint@620: M.set(v, true); jacint@620: } jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: jacint@620: ///Returns the inclusionwise maximum of the minimum value cuts. jacint@620: jacint@620: ///Sets \c M to the characteristic vector of the minimum value cut jacint@620: ///which is inclusionwise maximum. It is computed by processing a jacint@620: ///backward bfs from the target node \c t in the residual graph. jacint@620: ///\pre M should be a node map of bools initialized to false. jacint@620: ///\pre \c flow must be a maximum flow. jacint@620: template jacint@620: void maxMinCut(_CutMap& M) { jacint@620: jacint@620: NodeIt v; jacint@620: for(g->first(v) ; g->valid(v); g->next(v)) { jacint@620: M.set(v, true); jacint@620: } jacint@620: jacint@620: std::queue queue; jacint@620: jacint@620: M.set(t,false); jacint@620: queue.push(t); jacint@620: jacint@620: while (!queue.empty()) { jacint@620: Node w=queue.front(); jacint@620: queue.pop(); jacint@620: jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,w) ; g->valid(e); g->next(e)) { jacint@620: Node v=g->tail(e); jacint@620: if (M[v] && (*flow)[e] < (*capacity)[e] ) { jacint@620: queue.push(v); jacint@620: M.set(v, false); jacint@620: } jacint@620: } jacint@620: jacint@620: OutEdgeIt f; jacint@620: for(g->first(f,w) ; g->valid(f); g->next(f)) { jacint@620: Node v=g->head(f); jacint@620: if (M[v] && (*flow)[f] > 0 ) { jacint@620: queue.push(v); jacint@620: M.set(v, false); jacint@620: } jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: jacint@620: ///Returns a minimum value cut. jacint@620: jacint@620: ///Sets \c M to the characteristic vector of a minimum value cut. jacint@620: ///\pre M should be a node map of bools initialized to false. jacint@620: ///\pre \c flow must be a maximum flow. jacint@620: template jacint@620: void minCut(CutMap& M) { minMinCut(M); } jacint@620: jacint@620: ///Resets the source node to \c _s. jacint@620: jacint@620: ///Resets the source node to \c _s. jacint@620: /// jacint@620: void resetSource(Node _s) { s=_s; } jacint@620: jacint@620: jacint@620: ///Resets the target node to \c _t. jacint@620: jacint@620: ///Resets the target node to \c _t. jacint@620: /// jacint@620: void resetTarget(Node _t) { t=_t; } jacint@620: jacint@620: /// Resets the edge map of the capacities to _cap. jacint@620: jacint@620: /// Resets the edge map of the capacities to _cap. jacint@620: /// jacint@620: void resetCap(const CapMap& _cap) { capacity=&_cap; } jacint@620: jacint@620: /// Resets the edge map of the flows to _flow. jacint@620: jacint@620: /// Resets the edge map of the flows to _flow. jacint@620: /// jacint@620: void resetFlow(FlowMap& _flow) { flow=&_flow; } jacint@620: jacint@620: jacint@620: private: jacint@620: jacint@620: int push(Node w, VecStack& active) { jacint@620: jacint@620: int lev=level[w]; jacint@620: Num exc=excess[w]; jacint@620: int newlevel=n; //bound on the next level of w jacint@620: jacint@620: OutEdgeIt e; jacint@620: for(g->first(e,w); g->valid(e); g->next(e)) { jacint@620: jacint@620: if ( (*flow)[e] >= (*capacity)[e] ) continue; jacint@620: Node v=g->head(e); jacint@620: jacint@620: if( lev > level[v] ) { //Push is allowed now jacint@620: jacint@620: if ( excess[v]<=0 && v!=t && v!=s ) { jacint@620: int lev_v=level[v]; jacint@620: active[lev_v].push(v); jacint@620: } jacint@620: jacint@620: Num cap=(*capacity)[e]; jacint@620: Num flo=(*flow)[e]; jacint@620: Num remcap=cap-flo; jacint@620: jacint@620: if ( remcap >= exc ) { //A nonsaturating push. jacint@620: jacint@620: flow->set(e, flo+exc); jacint@620: excess.set(v, excess[v]+exc); jacint@620: exc=0; jacint@620: break; jacint@620: jacint@620: } else { //A saturating push. jacint@620: flow->set(e, cap); jacint@620: excess.set(v, excess[v]+remcap); jacint@620: exc-=remcap; jacint@620: } jacint@620: } else if ( newlevel > level[v] ) newlevel = level[v]; jacint@620: } //for out edges wv jacint@620: jacint@620: if ( exc > 0 ) { jacint@620: InEdgeIt e; jacint@620: for(g->first(e,w); g->valid(e); g->next(e)) { jacint@620: jacint@620: if( (*flow)[e] <= 0 ) continue; jacint@620: Node v=g->tail(e); jacint@620: jacint@620: if( lev > level[v] ) { //Push is allowed now jacint@620: jacint@620: if ( excess[v]<=0 && v!=t && v!=s ) { jacint@620: int lev_v=level[v]; jacint@620: active[lev_v].push(v); jacint@620: } jacint@620: jacint@620: Num flo=(*flow)[e]; jacint@620: jacint@620: if ( flo >= exc ) { //A nonsaturating push. jacint@620: jacint@620: flow->set(e, flo-exc); jacint@620: excess.set(v, excess[v]+exc); jacint@620: exc=0; jacint@620: break; jacint@620: } else { //A saturating push. jacint@620: jacint@620: excess.set(v, excess[v]+flo); jacint@620: exc-=flo; jacint@620: flow->set(e,0); jacint@620: } jacint@620: } else if ( newlevel > level[v] ) newlevel = level[v]; jacint@620: } //for in edges vw jacint@620: jacint@620: } // if w still has excess after the out edge for cycle jacint@620: jacint@620: excess.set(w, exc); jacint@620: jacint@620: return newlevel; jacint@620: } jacint@620: jacint@620: jacint@620: void preflowPreproc ( flowEnum fe, VecStack& active, jacint@620: VecNode& level_list, NNMap& left, NNMap& right ) { jacint@620: jacint@620: std::queue bfs_queue; jacint@620: jacint@620: switch ( fe ) { jacint@620: case ZERO_FLOW: jacint@620: { jacint@620: //Reverse_bfs from t, to find the starting level. jacint@620: level.set(t,0); jacint@620: bfs_queue.push(t); jacint@620: jacint@620: while (!bfs_queue.empty()) { jacint@620: jacint@620: Node v=bfs_queue.front(); jacint@620: bfs_queue.pop(); jacint@620: int l=level[v]+1; jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,v); g->valid(e); g->next(e)) { jacint@620: Node w=g->tail(e); jacint@620: if ( level[w] == n && w != s ) { jacint@620: bfs_queue.push(w); jacint@620: Node first=level_list[l]; jacint@620: if ( g->valid(first) ) left.set(first,w); jacint@620: right.set(w,first); jacint@620: level_list[l]=w; jacint@620: level.set(w, l); jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: //the starting flow jacint@620: OutEdgeIt e; jacint@620: for(g->first(e,s); g->valid(e); g->next(e)) jacint@620: { jacint@620: Num c=(*capacity)[e]; jacint@620: if ( c <= 0 ) continue; jacint@620: Node w=g->head(e); jacint@620: if ( level[w] < n ) { jacint@620: if ( excess[w] <= 0 && w!=t ) active[level[w]].push(w); jacint@620: flow->set(e, c); jacint@620: excess.set(w, excess[w]+c); jacint@620: } jacint@620: } jacint@620: break; jacint@620: } jacint@620: jacint@620: case GEN_FLOW: jacint@620: case PRE_FLOW: jacint@620: { jacint@620: //Reverse_bfs from t in the residual graph, jacint@620: //to find the starting level. jacint@620: level.set(t,0); jacint@620: bfs_queue.push(t); jacint@620: jacint@620: while (!bfs_queue.empty()) { jacint@620: jacint@620: Node v=bfs_queue.front(); jacint@620: bfs_queue.pop(); jacint@620: int l=level[v]+1; jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,v); g->valid(e); g->next(e)) { jacint@620: if ( (*capacity)[e] <= (*flow)[e] ) continue; jacint@620: Node w=g->tail(e); jacint@620: if ( level[w] == n && w != s ) { jacint@620: bfs_queue.push(w); jacint@620: Node first=level_list[l]; jacint@620: if ( g->valid(first) ) left.set(first,w); jacint@620: right.set(w,first); jacint@620: level_list[l]=w; jacint@620: level.set(w, l); jacint@620: } jacint@620: } jacint@620: jacint@620: OutEdgeIt f; jacint@620: for(g->first(f,v); g->valid(f); g->next(f)) { jacint@620: if ( 0 >= (*flow)[f] ) continue; jacint@620: Node w=g->head(f); jacint@620: if ( level[w] == n && w != s ) { jacint@620: bfs_queue.push(w); jacint@620: Node first=level_list[l]; jacint@620: if ( g->valid(first) ) left.set(first,w); jacint@620: right.set(w,first); jacint@620: level_list[l]=w; jacint@620: level.set(w, l); jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: jacint@620: //the starting flow jacint@620: OutEdgeIt e; jacint@620: for(g->first(e,s); g->valid(e); g->next(e)) jacint@620: { jacint@620: Num rem=(*capacity)[e]-(*flow)[e]; jacint@620: if ( rem <= 0 ) continue; jacint@620: Node w=g->head(e); jacint@620: if ( level[w] < n ) { jacint@620: if ( excess[w] <= 0 && w!=t ) active[level[w]].push(w); jacint@620: flow->set(e, (*capacity)[e]); jacint@620: excess.set(w, excess[w]+rem); jacint@620: } jacint@620: } jacint@620: jacint@620: InEdgeIt f; jacint@620: for(g->first(f,s); g->valid(f); g->next(f)) jacint@620: { jacint@620: if ( (*flow)[f] <= 0 ) continue; jacint@620: Node w=g->tail(f); jacint@620: if ( level[w] < n ) { jacint@620: if ( excess[w] <= 0 && w!=t ) active[level[w]].push(w); jacint@620: excess.set(w, excess[w]+(*flow)[f]); jacint@620: flow->set(f, 0); jacint@620: } jacint@620: } jacint@620: break; jacint@620: } //case PRE_FLOW jacint@620: } jacint@620: } //preflowPreproc jacint@620: jacint@620: jacint@620: jacint@620: void relabel(Node w, int newlevel, VecStack& active, jacint@620: VecNode& level_list, NNMap& left, jacint@620: NNMap& right, int& b, int& k, bool what_heur ) jacint@620: { jacint@620: jacint@620: Num lev=level[w]; jacint@620: jacint@620: Node right_n=right[w]; jacint@620: Node left_n=left[w]; jacint@620: jacint@620: //unlacing starts jacint@620: if ( g->valid(right_n) ) { jacint@620: if ( g->valid(left_n) ) { jacint@620: right.set(left_n, right_n); jacint@620: left.set(right_n, left_n); jacint@620: } else { jacint@620: level_list[lev]=right_n; jacint@620: left.set(right_n, INVALID); jacint@620: } jacint@620: } else { jacint@620: if ( g->valid(left_n) ) { jacint@620: right.set(left_n, INVALID); jacint@620: } else { jacint@620: level_list[lev]=INVALID; jacint@620: } jacint@620: } jacint@620: //unlacing ends jacint@620: jacint@620: if ( !g->valid(level_list[lev]) ) { jacint@620: jacint@620: //gapping starts jacint@620: for (int i=lev; i!=k ; ) { jacint@620: Node v=level_list[++i]; jacint@620: while ( g->valid(v) ) { jacint@620: level.set(v,n); jacint@620: v=right[v]; jacint@620: } jacint@620: level_list[i]=INVALID; jacint@620: if ( !what_heur ) { jacint@620: while ( !active[i].empty() ) { jacint@620: active[i].pop(); //FIXME: ezt szebben kene jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: level.set(w,n); jacint@620: b=lev-1; jacint@620: k=b; jacint@620: //gapping ends jacint@620: jacint@620: } else { jacint@620: jacint@620: if ( newlevel == n ) level.set(w,n); jacint@620: else { jacint@620: level.set(w,++newlevel); jacint@620: active[newlevel].push(w); jacint@620: if ( what_heur ) b=newlevel; jacint@620: if ( k < newlevel ) ++k; //now k=newlevel jacint@620: Node first=level_list[newlevel]; jacint@620: if ( g->valid(first) ) left.set(first,w); jacint@620: right.set(w,first); jacint@620: left.set(w,INVALID); jacint@620: level_list[newlevel]=w; jacint@620: } jacint@620: } jacint@620: jacint@620: } //relabel jacint@620: jacint@620: jacint@620: template jacint@620: class DistanceMap { jacint@620: protected: jacint@620: const MapGraphWrapper* g; jacint@620: typename MapGraphWrapper::template NodeMap dist; jacint@620: public: jacint@620: DistanceMap(MapGraphWrapper& _g) : g(&_g), dist(*g, g->nodeNum()) { } jacint@620: void set(const typename MapGraphWrapper::Node& n, int a) { jacint@620: dist.set(n, a); jacint@620: } jacint@620: int operator[](const typename MapGraphWrapper::Node& n) jacint@620: { return dist[n]; } jacint@620: // int get(const typename MapGraphWrapper::Node& n) const { jacint@620: // return dist[n]; } jacint@620: // bool get(const typename MapGraphWrapper::Edge& e) const { jacint@620: // return (dist.get(g->tail(e))head(e))); } jacint@620: bool operator[](const typename MapGraphWrapper::Edge& e) const { jacint@620: return (dist[g->tail(e)]head(e)]); jacint@620: } jacint@620: }; jacint@620: jacint@620: }; jacint@620: jacint@620: jacint@620: template jacint@620: void MaxFlow::preflowPhase1( flowEnum fe ) jacint@620: { jacint@620: jacint@620: int heur0=(int)(H0*n); //time while running 'bound decrease' jacint@620: int heur1=(int)(H1*n); //time while running 'highest label' jacint@620: int heur=heur1; //starting time interval (#of relabels) jacint@620: int numrelabel=0; jacint@620: jacint@620: bool what_heur=1; jacint@620: //It is 0 in case 'bound decrease' and 1 in case 'highest label' jacint@620: jacint@620: bool end=false; jacint@620: //Needed for 'bound decrease', true means no active nodes are above bound b. jacint@620: jacint@620: int k=n-2; //bound on the highest level under n containing a node jacint@620: int b=k; //bound on the highest level under n of an active node jacint@620: jacint@620: VecStack active(n); jacint@620: jacint@620: NNMap left(*g, INVALID); jacint@620: NNMap right(*g, INVALID); jacint@620: VecNode level_list(n,INVALID); jacint@620: //List of the nodes in level ifirst(v); g->valid(v); g->next(v)) level.set(v,n); jacint@620: //setting each node to level n jacint@620: jacint@620: switch ( fe ) { jacint@620: case PRE_FLOW: jacint@620: { jacint@620: //counting the excess jacint@620: NodeIt v; jacint@620: for(g->first(v); g->valid(v); g->next(v)) { jacint@620: Num exc=0; jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,v); g->valid(e); g->next(e)) exc+=(*flow)[e]; jacint@620: OutEdgeIt f; jacint@620: for(g->first(f,v); g->valid(f); g->next(f)) exc-=(*flow)[f]; jacint@620: jacint@620: excess.set(v,exc); jacint@620: jacint@620: //putting the active nodes into the stack jacint@620: int lev=level[v]; jacint@620: if ( exc > 0 && lev < n && v != t ) active[lev].push(v); jacint@620: } jacint@620: break; jacint@620: } jacint@620: case GEN_FLOW: jacint@620: { jacint@620: //Counting the excess of t jacint@620: Num exc=0; jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,t); g->valid(e); g->next(e)) exc+=(*flow)[e]; jacint@620: OutEdgeIt f; jacint@620: for(g->first(f,t); g->valid(f); g->next(f)) exc-=(*flow)[f]; jacint@620: jacint@620: excess.set(t,exc); jacint@620: jacint@620: break; jacint@620: } jacint@620: default: jacint@620: break; jacint@620: } jacint@620: jacint@620: preflowPreproc( fe, active, level_list, left, right ); jacint@620: //End of preprocessing jacint@620: jacint@620: jacint@620: //Push/relabel on the highest level active nodes. jacint@620: while ( true ) { jacint@620: if ( b == 0 ) { jacint@620: if ( !what_heur && !end && k > 0 ) { jacint@620: b=k; jacint@620: end=true; jacint@620: } else break; jacint@620: } jacint@620: jacint@620: if ( active[b].empty() ) --b; jacint@620: else { jacint@620: end=false; jacint@620: Node w=active[b].top(); jacint@620: active[b].pop(); jacint@620: int newlevel=push(w,active); jacint@620: if ( excess[w] > 0 ) relabel(w, newlevel, active, level_list, jacint@620: left, right, b, k, what_heur); jacint@620: jacint@620: ++numrelabel; jacint@620: if ( numrelabel >= heur ) { jacint@620: numrelabel=0; jacint@620: if ( what_heur ) { jacint@620: what_heur=0; jacint@620: heur=heur0; jacint@620: end=false; jacint@620: } else { jacint@620: what_heur=1; jacint@620: heur=heur1; jacint@620: b=k; jacint@620: } jacint@620: } jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: jacint@620: jacint@620: template jacint@620: void MaxFlow::preflowPhase2() jacint@620: { jacint@620: jacint@620: int k=n-2; //bound on the highest level under n containing a node jacint@620: int b=k; //bound on the highest level under n of an active node jacint@620: jacint@620: VecStack active(n); jacint@620: level.set(s,0); jacint@620: std::queue bfs_queue; jacint@620: bfs_queue.push(s); jacint@620: jacint@620: while (!bfs_queue.empty()) { jacint@620: jacint@620: Node v=bfs_queue.front(); jacint@620: bfs_queue.pop(); jacint@620: int l=level[v]+1; jacint@620: jacint@620: InEdgeIt e; jacint@620: for(g->first(e,v); g->valid(e); g->next(e)) { jacint@620: if ( (*capacity)[e] <= (*flow)[e] ) continue; jacint@620: Node u=g->tail(e); jacint@620: if ( level[u] >= n ) { jacint@620: bfs_queue.push(u); jacint@620: level.set(u, l); jacint@620: if ( excess[u] > 0 ) active[l].push(u); jacint@620: } jacint@620: } jacint@620: jacint@620: OutEdgeIt f; jacint@620: for(g->first(f,v); g->valid(f); g->next(f)) { jacint@620: if ( 0 >= (*flow)[f] ) continue; jacint@620: Node u=g->head(f); jacint@620: if ( level[u] >= n ) { jacint@620: bfs_queue.push(u); jacint@620: level.set(u, l); jacint@620: if ( excess[u] > 0 ) active[l].push(u); jacint@620: } jacint@620: } jacint@620: } jacint@620: b=n-2; jacint@620: jacint@620: while ( true ) { jacint@620: jacint@620: if ( b == 0 ) break; jacint@620: jacint@620: if ( active[b].empty() ) --b; jacint@620: else { jacint@620: Node w=active[b].top(); jacint@620: active[b].pop(); jacint@620: int newlevel=push(w,active); jacint@620: jacint@620: //relabel jacint@620: if ( excess[w] > 0 ) { jacint@620: level.set(w,++newlevel); jacint@620: active[newlevel].push(w); jacint@620: b=newlevel; jacint@620: } jacint@620: } // if stack[b] is nonempty jacint@620: } // while(true) jacint@620: } jacint@620: jacint@620: jacint@620: jacint@620: template jacint@620: bool MaxFlow::augmentOnShortestPath() jacint@620: { jacint@620: ResGW res_graph(*g, *capacity, *flow); jacint@620: bool _augment=false; jacint@620: jacint@620: //ReachedMap level(res_graph); jacint@620: FOR_EACH_LOC(typename Graph::NodeIt, e, *g) level.set(e, 0); jacint@620: BfsIterator bfs(res_graph, level); jacint@620: bfs.pushAndSetReached(s); jacint@620: jacint@620: typename ResGW::template NodeMap pred(res_graph); jacint@620: pred.set(s, INVALID); jacint@620: jacint@620: typename ResGW::template NodeMap free(res_graph); jacint@620: jacint@620: //searching for augmenting path jacint@620: while ( !bfs.finished() ) { jacint@620: ResGWOutEdgeIt e=bfs; jacint@620: if (res_graph.valid(e) && bfs.isBNodeNewlyReached()) { jacint@620: Node v=res_graph.tail(e); jacint@620: Node w=res_graph.head(e); jacint@620: pred.set(w, e); jacint@620: if (res_graph.valid(pred[v])) { jacint@620: free.set(w, std::min(free[v], res_graph.resCap(e))); jacint@620: } else { jacint@620: free.set(w, res_graph.resCap(e)); jacint@620: } jacint@620: if (res_graph.head(e)==t) { _augment=true; break; } jacint@620: } jacint@620: jacint@620: ++bfs; jacint@620: } //end of searching augmenting path jacint@620: jacint@620: if (_augment) { jacint@620: Node n=t; jacint@620: Num augment_value=free[t]; jacint@620: while (res_graph.valid(pred[n])) { jacint@620: ResGWEdge e=pred[n]; jacint@620: res_graph.augment(e, augment_value); jacint@620: n=res_graph.tail(e); jacint@620: } jacint@620: } jacint@620: jacint@620: return _augment; jacint@620: } jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: template jacint@620: template jacint@620: bool MaxFlow::augmentOnBlockingFlow() jacint@620: { jacint@620: typedef MutableGraph MG; jacint@620: bool _augment=false; jacint@620: jacint@620: ResGW res_graph(*g, *capacity, *flow); jacint@620: jacint@620: //bfs for distances on the residual graph jacint@620: //ReachedMap level(res_graph); jacint@620: FOR_EACH_LOC(typename Graph::NodeIt, e, *g) level.set(e, 0); jacint@620: BfsIterator bfs(res_graph, level); jacint@620: bfs.pushAndSetReached(s); jacint@620: typename ResGW::template NodeMap jacint@620: dist(res_graph); //filled up with 0's jacint@620: jacint@620: //F will contain the physical copy of the residual graph jacint@620: //with the set of edges which are on shortest paths jacint@620: MG F; jacint@620: typename ResGW::template NodeMap jacint@620: res_graph_to_F(res_graph); jacint@620: { jacint@620: typename ResGW::NodeIt n; jacint@620: for(res_graph.first(n); res_graph.valid(n); res_graph.next(n)) { jacint@620: res_graph_to_F.set(n, F.addNode()); jacint@620: } jacint@620: } jacint@620: jacint@620: typename MG::Node sF=res_graph_to_F[s]; jacint@620: typename MG::Node tF=res_graph_to_F[t]; jacint@620: typename MG::template EdgeMap original_edge(F); jacint@620: typename MG::template EdgeMap residual_capacity(F); jacint@620: jacint@620: while ( !bfs.finished() ) { jacint@620: ResGWOutEdgeIt e=bfs; jacint@620: if (res_graph.valid(e)) { jacint@620: if (bfs.isBNodeNewlyReached()) { jacint@620: dist.set(res_graph.head(e), dist[res_graph.tail(e)]+1); jacint@620: typename MG::Edge f=F.addEdge(res_graph_to_F[res_graph.tail(e)], res_graph_to_F[res_graph.head(e)]); jacint@620: original_edge.update(); jacint@620: original_edge.set(f, e); jacint@620: residual_capacity.update(); jacint@620: residual_capacity.set(f, res_graph.resCap(e)); jacint@620: } else { jacint@620: if (dist[res_graph.head(e)]==(dist[res_graph.tail(e)]+1)) { jacint@620: typename MG::Edge f=F.addEdge(res_graph_to_F[res_graph.tail(e)], res_graph_to_F[res_graph.head(e)]); jacint@620: original_edge.update(); jacint@620: original_edge.set(f, e); jacint@620: residual_capacity.update(); jacint@620: residual_capacity.set(f, res_graph.resCap(e)); jacint@620: } jacint@620: } jacint@620: } jacint@620: ++bfs; jacint@620: } //computing distances from s in the residual graph jacint@620: jacint@620: bool __augment=true; jacint@620: jacint@620: while (__augment) { jacint@620: __augment=false; jacint@620: //computing blocking flow with dfs jacint@620: DfsIterator< MG, typename MG::template NodeMap > dfs(F); jacint@620: typename MG::template NodeMap pred(F); jacint@620: pred.set(sF, INVALID); jacint@620: //invalid iterators for sources jacint@620: jacint@620: typename MG::template NodeMap free(F); jacint@620: jacint@620: dfs.pushAndSetReached(sF); jacint@620: while (!dfs.finished()) { jacint@620: ++dfs; jacint@620: if (F.valid(/*typename MG::OutEdgeIt*/(dfs))) { jacint@620: if (dfs.isBNodeNewlyReached()) { jacint@620: typename MG::Node v=F.aNode(dfs); jacint@620: typename MG::Node w=F.bNode(dfs); jacint@620: pred.set(w, dfs); jacint@620: if (F.valid(pred[v])) { jacint@620: free.set(w, std::min(free[v], residual_capacity[dfs])); jacint@620: } else { jacint@620: free.set(w, residual_capacity[dfs]); jacint@620: } jacint@620: if (w==tF) { jacint@620: __augment=true; jacint@620: _augment=true; jacint@620: break; jacint@620: } jacint@620: jacint@620: } else { jacint@620: F.erase(/*typename MG::OutEdgeIt*/(dfs)); jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: if (__augment) { jacint@620: typename MG::Node n=tF; jacint@620: Num augment_value=free[tF]; jacint@620: while (F.valid(pred[n])) { jacint@620: typename MG::Edge e=pred[n]; jacint@620: res_graph.augment(original_edge[e], augment_value); jacint@620: n=F.tail(e); jacint@620: if (residual_capacity[e]==augment_value) jacint@620: F.erase(e); jacint@620: else jacint@620: residual_capacity.set(e, residual_capacity[e]-augment_value); jacint@620: } jacint@620: } jacint@620: jacint@620: } jacint@620: jacint@620: return _augment; jacint@620: } jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: jacint@620: template jacint@620: bool MaxFlow::augmentOnBlockingFlow2() jacint@620: { jacint@620: bool _augment=false; jacint@620: jacint@620: ResGW res_graph(*g, *capacity, *flow); jacint@620: jacint@620: //ReachedMap level(res_graph); jacint@620: FOR_EACH_LOC(typename Graph::NodeIt, e, *g) level.set(e, 0); jacint@620: BfsIterator bfs(res_graph, level); jacint@620: jacint@620: bfs.pushAndSetReached(s); jacint@620: DistanceMap dist(res_graph); jacint@620: while ( !bfs.finished() ) { jacint@620: ResGWOutEdgeIt e=bfs; jacint@620: if (res_graph.valid(e) && bfs.isBNodeNewlyReached()) { jacint@620: dist.set(res_graph.head(e), dist[res_graph.tail(e)]+1); jacint@620: } jacint@620: ++bfs; jacint@620: } //computing distances from s in the residual graph jacint@620: jacint@620: //Subgraph containing the edges on some shortest paths jacint@620: ConstMap true_map(true); jacint@620: typedef SubGraphWrapper, jacint@620: DistanceMap > FilterResGW; jacint@620: FilterResGW filter_res_graph(res_graph, true_map, dist); jacint@620: jacint@620: //Subgraph, which is able to delete edges which are already jacint@620: //met by the dfs jacint@620: typename FilterResGW::template NodeMap jacint@620: first_out_edges(filter_res_graph); jacint@620: typename FilterResGW::NodeIt v; jacint@620: for(filter_res_graph.first(v); filter_res_graph.valid(v); jacint@620: filter_res_graph.next(v)) jacint@620: { jacint@620: typename FilterResGW::OutEdgeIt e; jacint@620: filter_res_graph.first(e, v); jacint@620: first_out_edges.set(v, e); jacint@620: } jacint@620: typedef ErasingFirstGraphWrapper > ErasingResGW; jacint@620: ErasingResGW erasing_res_graph(filter_res_graph, first_out_edges); jacint@620: jacint@620: bool __augment=true; jacint@620: jacint@620: while (__augment) { jacint@620: jacint@620: __augment=false; jacint@620: //computing blocking flow with dfs jacint@620: DfsIterator< ErasingResGW, jacint@620: typename ErasingResGW::template NodeMap > jacint@620: dfs(erasing_res_graph); jacint@620: typename ErasingResGW:: jacint@620: template NodeMap jacint@620: pred(erasing_res_graph); jacint@620: pred.set(s, INVALID); jacint@620: //invalid iterators for sources jacint@620: jacint@620: typename ErasingResGW::template NodeMap jacint@620: free1(erasing_res_graph); jacint@620: jacint@620: dfs.pushAndSetReached( jacint@620: typename ErasingResGW::Node( jacint@620: typename FilterResGW::Node( jacint@620: typename ResGW::Node(s) jacint@620: ) jacint@620: ) jacint@620: ); jacint@620: while (!dfs.finished()) { jacint@620: ++dfs; jacint@620: if (erasing_res_graph.valid( jacint@620: typename ErasingResGW::OutEdgeIt(dfs))) jacint@620: { jacint@620: if (dfs.isBNodeNewlyReached()) { jacint@620: jacint@620: typename ErasingResGW::Node v=erasing_res_graph.aNode(dfs); jacint@620: typename ErasingResGW::Node w=erasing_res_graph.bNode(dfs); jacint@620: jacint@620: pred.set(w, /*typename ErasingResGW::OutEdgeIt*/(dfs)); jacint@620: if (erasing_res_graph.valid(pred[v])) { jacint@620: free1.set(w, std::min(free1[v], res_graph.resCap( jacint@620: typename ErasingResGW::OutEdgeIt(dfs)))); jacint@620: } else { jacint@620: free1.set(w, res_graph.resCap( jacint@620: typename ErasingResGW::OutEdgeIt(dfs))); jacint@620: } jacint@620: jacint@620: if (w==t) { jacint@620: __augment=true; jacint@620: _augment=true; jacint@620: break; jacint@620: } jacint@620: } else { jacint@620: erasing_res_graph.erase(dfs); jacint@620: } jacint@620: } jacint@620: } jacint@620: jacint@620: if (__augment) { jacint@620: typename ErasingResGW::Node n=typename FilterResGW::Node(typename ResGW::Node(t)); jacint@620: // typename ResGW::NodeMap a(res_graph); jacint@620: // typename ResGW::Node b; jacint@620: // Num j=a[b]; jacint@620: // typename FilterResGW::NodeMap a1(filter_res_graph); jacint@620: // typename FilterResGW::Node b1; jacint@620: // Num j1=a1[b1]; jacint@620: // typename ErasingResGW::NodeMap a2(erasing_res_graph); jacint@620: // typename ErasingResGW::Node b2; jacint@620: // Num j2=a2[b2]; jacint@620: Num augment_value=free1[n]; jacint@620: while (erasing_res_graph.valid(pred[n])) { jacint@620: typename ErasingResGW::OutEdgeIt e=pred[n]; jacint@620: res_graph.augment(e, augment_value); jacint@620: n=erasing_res_graph.tail(e); jacint@620: if (res_graph.resCap(e)==0) jacint@620: erasing_res_graph.erase(e); jacint@620: } jacint@620: } jacint@620: jacint@620: } //while (__augment) jacint@620: jacint@620: return _augment; jacint@620: } jacint@620: jacint@620: jacint@620: jacint@620: /// @} jacint@620: jacint@620: } //END OF NAMESPACE HUGO jacint@620: jacint@620: #endif //HUGO_MAX_FLOW_H jacint@620: jacint@620: jacint@620: jacint@620: