// -*- C++ -*- /* preflow_hl2.h by jacint. Runs the highest label variant of the preflow push algorithm with running time O(n^2\sqrt(m)), with the 'empty level' and with the heuristic that the bound b on the active nodes is not increased only when b=0, when we put b=2*n-2. 'A' is a parameter for the empty_level heuristic Member functions: void run() : runs the algorithm The following functions should be used after run() was already run. T maxflow() : returns the value of a maximum flow T flowonedge(EdgeIt e) : for a fixed maximum flow x it returns x(e) FlowMap allflow() : returns the fixed maximum flow x void mincut(CutMap& M) : sets M to the characteristic vector of a minimum cut. M should be a map of bools initialized to false. void min_mincut(CutMap& M) : sets M to the characteristic vector of the minimum min cut. M should be a map of bools initialized to false. void max_mincut(CutMap& M) : sets M to the characteristic vector of the maximum min cut. M should be a map of bools initialized to false. */ #ifndef PREFLOW_HL2_H #define PREFLOW_HL2_H #define A 1 #include #include #include namespace marci { template , typename CapMap=typename Graph::EdgeMap, typename IntMap=typename Graph::NodeMap, typename TMap=typename Graph::NodeMap > class preflow_hl2 { typedef typename Graph::NodeIt NodeIt; typedef typename Graph::EdgeIt EdgeIt; typedef typename Graph::EachNodeIt EachNodeIt; typedef typename Graph::OutEdgeIt OutEdgeIt; typedef typename Graph::InEdgeIt InEdgeIt; Graph& G; NodeIt s; NodeIt t; FlowMap flow; CapMap& capacity; T value; public: preflow_hl2(Graph& _G, NodeIt _s, NodeIt _t, CapMap& _capacity) : G(_G), s(_s), t(_t), flow(_G, 0), capacity(_capacity) { } void run() { bool no_end=true; int n=G.nodeNum(); int b=n-2; /* b is a bound on the highest level of an active node. In the beginning it is at most n-2. */ IntMap level(G,n); TMap excess(G); std::vector numb(n+1); /* The number of nodes on level i < n. It is initialized to n+1, because of the reverse_bfs-part. */ std::vector > stack(2*n-1); //Stack of the active nodes in level i. /*Reverse_bfs from t, to find the starting level.*/ level.set(t,0); std::queue bfs_queue; bfs_queue.push(t); while (!bfs_queue.empty()) { NodeIt v=bfs_queue.front(); bfs_queue.pop(); int l=level.get(v)+1; for(InEdgeIt e=G.template first(v); e.valid(); ++e) { NodeIt w=G.tail(e); if ( level.get(w) == n ) { bfs_queue.push(w); ++numb[l]; level.set(w, l); } } } level.set(s,n); /* Starting flow. It is everywhere 0 at the moment. */ for(OutEdgeIt e=G.template first(s); e.valid(); ++e) { if ( capacity.get(e) == 0 ) continue; NodeIt w=G.head(e); if ( w!=s ) { if ( excess.get(w) == 0 && w!=t ) stack[level.get(w)].push(w); flow.set(e, capacity.get(e)); excess.set(w, excess.get(w)+capacity.get(e)); } } /* End of preprocessing */ /* Push/relabel on the highest level active nodes. */ /*While there exists an active node.*/ while (b) { if ( stack[b].empty() ) { if ( b==1 ) { if ( !no_end ) break; else { b=2*n-2; no_end=false; } } --b; } else { no_end=true; NodeIt w=stack[b].top(); //w is a highest label active node. stack[b].pop(); int lev=level.get(w); int exc=excess.get(w); int newlevel=2*n-2; //In newlevel we bound the next level of w. // if ( level.get(w) < n ) { //Nem tudom ez mukodik-e for(OutEdgeIt e=G.template first(w); e.valid(); ++e) { if ( flow.get(e) == capacity.get(e) ) continue; NodeIt v=G.head(e); //e=wv if( lev > level.get(v) ) { /*Push is allowed now*/ if ( excess.get(v)==0 && v != s && v !=t ) stack[level.get(v)].push(v); /*v becomes active.*/ int cap=capacity.get(e); int flo=flow.get(e); int remcap=cap-flo; if ( remcap >= exc ) { /*A nonsaturating push.*/ flow.set(e, flo+exc); excess.set(v, excess.get(v)+exc); exc=0; break; } else { /*A saturating push.*/ flow.set(e, cap ); excess.set(v, excess.get(v)+remcap); exc-=remcap; } } else if ( newlevel > level.get(v) ) newlevel = level.get(v); } //for out edges wv if ( exc > 0 ) { for( InEdgeIt e=G.template first(w); e.valid(); ++e) { if( flow.get(e) == 0 ) continue; NodeIt v=G.tail(e); //e=vw if( lev > level.get(v) ) { /*Push is allowed now*/ if ( excess.get(v)==0 && v != s && v !=t) stack[level.get(v)].push(v); /*v becomes active.*/ int flo=flow.get(e); if ( flo >= exc ) { /*A nonsaturating push.*/ flow.set(e, flo-exc); excess.set(v, excess.get(v)+exc); exc=0; break; } else { /*A saturating push.*/ excess.set(v, excess.get(v)+flo); exc-=flo; flow.set(e,0); } } else if ( newlevel > level.get(v) ) newlevel = level.get(v); } //for in edges vw } // if w still has excess after the out edge for cycle excess.set(w, exc); /* Relabel */ if ( exc > 0 ) { //now 'lev' is the old level of w level.set(w,++newlevel); if ( lev < n ) { --numb[lev]; if ( !numb[lev] && lev < A*n ) { //If the level of w gets empty. for (EachNodeIt v=G.template first(); v.valid() ; ++v) { if (level.get(v) > lev && level.get(v) < n ) level.set(v,n); } for (int i=lev+1 ; i!=n ; ++i) numb[i]=0; if ( newlevel < n ) newlevel=n; } else { if ( newlevel < n ) ++numb[newlevel]; } } stack[newlevel].push(w); } } // if stack[b] is nonempty } // while(b) value = excess.get(t); /*Max flow value.*/ } //void run() /* Returns the maximum value of a flow. */ T maxflow() { return value; } /* For the maximum flow x found by the algorithm, it returns the flow value on Edge e, i.e. x(e). */ T flowonedge(EdgeIt e) { return flow.get(e); } /* Returns the maximum flow x found by the algorithm. */ FlowMap allflow() { return flow; } /* Returns the minimum min cut, by a bfs from s in the residual graph. */ template void mincut(CutMap& M) { std::queue queue; M.set(s,true); queue.push(s); while (!queue.empty()) { NodeIt w=queue.front(); queue.pop(); for(OutEdgeIt e=G.template first(w) ; e.valid(); ++e) { NodeIt v=G.head(e); if (!M.get(v) && flow.get(e) < capacity.get(e) ) { queue.push(v); M.set(v, true); } } for(InEdgeIt e=G.template first(w) ; e.valid(); ++e) { NodeIt v=G.tail(e); if (!M.get(v) && flow.get(e) > 0 ) { queue.push(v); M.set(v, true); } } } } /* Returns the maximum min cut, by a reverse bfs from t in the residual graph. */ template void max_mincut(CutMap& M) { std::queue queue; M.set(t,true); queue.push(t); while (!queue.empty()) { NodeIt w=queue.front(); queue.pop(); for(InEdgeIt e=G.template first(w) ; e.valid(); ++e) { NodeIt v=G.tail(e); if (!M.get(v) && flow.get(e) < capacity.get(e) ) { queue.push(v); M.set(v, true); } } for(OutEdgeIt e=G.template first(w) ; e.valid(); ++e) { NodeIt v=G.head(e); if (!M.get(v) && flow.get(e) > 0 ) { queue.push(v); M.set(v, true); } } } for(EachNodeIt v=G.template first() ; v.valid(); ++v) { M.set(v, !M.get(v)); } } template void min_mincut(CutMap& M) { mincut(M); } }; }//namespace marci #endif