home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************************************
- +
- + LEDA 2.1.1 11-15-1991
- +
- +
- + _maxflow.c
- +
- +
- + Copyright (c) 1991 by Max-Planck-Institut fuer Informatik
- + Im Stadtwald, 6600 Saarbruecken, FRG
- + All rights reserved.
- +
- *******************************************************************************/
-
-
- /******************************************************************************\
- * *
- * MAX_FLOW *
- * *
- * Max Flow Algorithm, using the Goldberg-Tarjan algorithm, Journal ACM 35, *
- * Oct 1988, p921-940 . *
- * *
- * Applies push steps to vertices with positive preflow, based on *
- * distance labels. Uses FIFO rule (implemented by FIFO queue) *
- * for selecting a vertex with +ve preflow. ) *
- * *
- * *
- * Implemented by *
- * *
- * Joseph Cheriyan & Stefan Naeher *
- * *
- * Fachbereich Informatik *
- * Universitaet des Saarlandes *
- * 6600 Saarbruecken *
- * *
- \******************************************************************************/
-
- #include <LEDA/graph_alg.h>
-
- static
- void gt_bfs2(node s_vert, int dist_s_vert,
- const graph& G, node s, const edge_array(int)& cap,
- edge_array(int)& flow, node_array(int)& dist);
-
-
- int MAX_FLOW(graph& G, node s, node t, const edge_array(int)& cap,
- edge_array(int)& flow)
- {
-
- /* Computes a maximum flow from source s to sink t, using
- Goldberg-Tarjan algorithm [Journal ACM 35 (Oct 1988) p921-940].
- ( Applies push steps to vertices with positive preflow, based on
- distance labels. Uses FIFO rule (implemented by FIFO queue)
- for selecting a vertex with +ve preflow. )
-
- input: cap[e] gives capacity of edge e
-
- output: flow[e] flow on edge e
- returns total flow into sink
-
- node_arrays used by the algorithm:
- dist[v] = lower bound on shortest distance from v to t
- excess[v] = (total incoming preflow[v]) - (total outgoing preflow[v])
-
- Implemented by Joseph Cheriyan & Stefan Naeher.
- */
-
-
- int heuristic = 1;
-
- /*
- heuristic == parameter for heuristic suggested by Goldberg
- to speed up algorithm
- 0 == no heuristic
- 1 == compute exact distance labels after every N relabel steps
- +i == compute exact distance labels after every N*i relabel steps
- -i == compute exact distance labels after every N/i relabel steps
-
- */
-
- node_array(int) dist(G,0);
- node_array(int) excess(G,0);
-
- list(node) U; // FIFO Queue used for selecting vertex with +ve preflow
- node v,w;
- edge e;
-
- G.make_undirected();
-
- int N = G.number_of_nodes();
-
- int num_relabels = 0;
-
- if (heuristic < -N || heuristic > N)
- heuristic = 0;
- else
- heuristic = ((heuristic >= 0) ? N*heuristic : N/(-heuristic));
-
- int limit_heur = heuristic;
-
- if (s == t) error_handler(1,"gt_max_flow: source == sink");
-
- forall_edges(e,G) flow[e] = 0;
-
- forall_adj_edges(e,s)
- if (source(e) == s)
- { v = target(e);
- flow[e] = cap[e];
- excess[v] += flow[e];
- if (v!=s && v!=t) U.append(v);
- }
-
- dist[s] = N;
-
- while (! U.empty() ) /* main loop */
- {
- v = U.pop();
-
- int delta;
-
- while ((excess[v] > 0) && G.next_adj_edge(e,v))
- { // push flow along each edge e = (v,w) in the residual graph with
- // dist[v] == dist[w] + 1
-
- if (v == source(e))
- { w = target(e);
-
- if ((dist[v]==dist[w]+1)
- && (delta = Min(cap[e]-flow[e],excess[v]))
- && (dist[v] < N))
- // pushes towards s that increase flow[e] are not allowed
-
- { if ((excess[w] == 0) && (w != t)) U.append(w);
- flow[e] += delta;
- excess[w] += delta;
- excess[v] -= delta;
- }
- }
- else
- { w = source(e);
- if ((dist[v] == dist[w]+1) && (delta = Min(flow[e],excess[v])))
- { if ((excess[w] == 0) && (w != t) && (w != s)) U.append(w);
- flow[e] -= delta;
- excess[w] += delta;
- excess[v] -= delta;
- }
- }
-
- } // while ( (excess[v] > 0) && ...)
-
-
- if (excess[v] > 0)
- {
- // relabel vertex v (i.e. update dist[v]) because all
- // admissible edges in the residual graph have been saturated
-
- num_relabels++;
-
- if ( heuristic
- && (num_relabels == limit_heur))
- {
- limit_heur += heuristic;
-
- // heuristic suggested by Goldberg to reduce number of relabels:
- // periodically compute exact dist[] labels by two backward bfs
- // one starting at t and another starting at s
-
- node x;
-
- forall_nodes(x,G)
- dist[x] = Infinity;
-
- gt_bfs2(t,0,G,s,cap,flow,dist);
- gt_bfs2(s,N,G,s,cap,flow,dist);
-
- }
-
- else
-
- {
- int min_dist = Infinity;
- forall_adj_edges(e,v)
- {
- if ((source(e) == v) && ((cap[e] - flow[e]) > 0) && (dist[v] < N))
- //pushes towards s that increase flow[e] are not allowed
- min_dist = Min(min_dist,dist[target(e)]);
-
- if ((target(e) == v) && (flow[e] > 0))
- min_dist = Min(min_dist,dist[source(e)]);
- }
- if (min_dist != Infinity) min_dist++;
- dist[v] = min_dist;
-
- } // else
-
- U.push(v);
- G.init_adj_iterator(v);
-
- } // if (excess[v] > 0)
-
- } // while (!U.empty())
-
-
-
- //code to verify that flow is legal
-
-
- /*
- int tot_s_flow = 0;
- forall_adj_edges(e,s)
- if (source(e) == s) tot_s_flow += cap[e];
- if (tot_s_flow != (excess[s] + excess[t]))
- { cout << "gt_max_flow: total out cap s != excess[s] + excess[t]\n";
- forall_nodes(v,G)
- if ((excess[v] != 0) && (v != t) && (v != s))
- cout << "gt_max_flow: v!=s,t has excess[v]=" << excess[v] << "\n";
- }
- */
-
-
- G.make_directed();
-
- heuristic = num_relabels;
-
- int result = excess[t]; //returns value of maximum flow from s to t
-
- return result;
-
- } // procedure gt_max_flow
-
-
- //procedure to perform backward bfs starting at vertex s_vert with
- //distance label dist_s_vert
-
- static
- void gt_bfs2(node s_vert, int dist_s_vert,
- const graph& G, node s, const edge_array(int)& cap,
- edge_array(int)& flow, node_array(int)& dist)
- {
- node x,y;
- edge e;
- list(node) bfs_Q;
- int c;
-
- dist[s_vert] = dist_s_vert;
- bfs_Q.append(s_vert);
- while (x = bfs_Q.pop())
- {
- forall_adj_edges(e,x)
- {
- if (x == source(e))
- { y = target(e);
- c = flow[e]; }
- else
- { y = source(e);
- c = cap[e] - flow[e]; }
-
- if ( c > 0 && dist[y] == Infinity
- && !(x == target(e) && (s_vert == s)) )
- // while doing bfs with s_vert==s,
- // only edges with flow[e]>0 are reachable from s
-
- { dist[y] = dist[x] + 1;
- bfs_Q.append(y);
- G.init_adj_iterator(y);
-
- //next statement is not really needed, but is added for
- //protection, to ensure that s does not get relabelled by
- //bfs starting at t; this may lead to decrease in d[v]!
- if (y == s) dist[y] = G.number_of_nodes();
- }
-
- } //forall (e,...)
-
- } //while (x == bfs_Q.pop())
-
- } //end gt_bfs2
-
-
-
-
-
-
- #ifndef NO_REAL_GRAPH_ALG
-
-
- static
- void gt_bfs1(node s_vert, int dist_s_vert,
- const graph& G, node s, const edge_array(real)& cap,
- edge_array(real)& flow, node_array(int)& dist);
-
-
-
- real MAX_FLOW(graph& G, node s, node t, const edge_array(real)& cap,
- edge_array(real)& flow)
- {
- int heuristic = 1;
-
- /* Computes a maximum flow from source s to sink t, using
- Goldberg-Tarjan algorithm [Journal ACM 35 (Oct 1988) p921-940].
- ( Applies push steps to vertices with positive preflow, based on
- distance labels. Uses FIFO rule (implemented by FIFO queue)
- for selecting a vertex with +ve preflow. )
-
- input: cap[e] gives capacity of edge e
-
- heuristic == parameter for heuristic suggested by Goldberg
- to speed up algorithm
- 0 == no heuristic
- 1 == compute exact distance labels after every N relabel steps
- +i == compute exact distance labels after every N*i relabel steps
- -i == compute exact distance labels after every N/i relabel steps
-
- output: flow[e] flow on edge e
- heuristic = number of relabels
-
- returns total flow into sink
-
- node_arrays used by the algorithm:
- dist[v] = lower bound on shortest distance from v to t
- excess[v] = (total incoming preflow[v]) - (total outgoing preflow[v])
-
- Implemented by Joseph Cheriyan & Stefan Naeher.
- */
-
-
-
- node_array(int) dist(G,0);
- node_array(real) excess(G,0);
-
- list(node) U; // FIFO Queue used for selecting vertex with +ve preflow
- node v,w;
- edge e;
-
- G.make_undirected();
-
- int N = G.number_of_nodes();
-
- int num_relabels = 0;
-
- if (heuristic < -N || heuristic > N)
- heuristic = 0;
- else
- heuristic = ((heuristic >= 0) ? N*heuristic : N/(-heuristic));
-
- int limit_heur = heuristic;
-
- if (s == t) error_handler(1,"gt_max_flow: source == sink");
-
- forall_edges(e,G) flow[e] = 0;
-
- forall_adj_edges(e,s)
- if (source(e) == s)
- { v = target(e);
- flow[e] = cap[e];
- excess[v] += flow[e];
- if (v!=s && v!=t) U.append(v);
- }
-
- dist[s] = N;
-
- while (! U.empty() ) /* main loop */
- {
- v = U.pop();
-
- real delta;
-
- while ((excess[v] > 0) && G.next_adj_edge(e,v))
- { // push flow along each edge e = (v,w) in the residual graph with
- // dist[v] == dist[w] + 1
-
- if (v == source(e))
- { w = target(e);
- real d = cap[e] - flow[e];
- delta = Min(d,excess[v]);
- if ((dist[v]==dist[w]+1) && (delta > 0) && (dist[v] < N))
- // pushes towards s that increase flow[e] are not allowed
- { if ((excess[w] == 0) && (w != t)) U.append(w);
- flow[e] += delta;
- excess[w] += delta;
- excess[v] -= delta;
- }
- }
- else
- { w = source(e);
- delta = Min(flow[e],excess[v]);
- if ((dist[v] == dist[w]+1) && (delta > 0))
- { if ((excess[w] == 0) && (w != t) && (w != s)) U.append(w);
- flow[e] -= delta;
- excess[w] += delta;
- excess[v] -= delta;
- }
- }
-
- } // while ( (excess[v] > 0) && ...)
-
-
- if (excess[v] > 0)
- {
- // relabel vertex v (i.e. update dist[v]) because all
- // admissible edges in the residual graph have been saturated
-
- num_relabels++;
-
- if ( heuristic
- && (num_relabels == limit_heur))
- {
- limit_heur += heuristic;
-
- // heuristic suggested by Goldberg to reduce number of relabels:
- // periodically compute exact dist[] labels by two backward bfs
- // one starting at t and another starting at s
-
- node x;
-
- forall_nodes(x,G)
- dist[x] = Infinity;
-
- gt_bfs1(t,0,G,s,cap,flow,dist);
- gt_bfs1(s,N,G,s,cap,flow,dist);
-
- }
-
- else
-
- {
- int min_dist = Infinity;
- forall_adj_edges(e,v)
- {
- real r = cap[e] - flow[e];
-
- if ((source(e) == v) && (r > 0) && (dist[v] < N))
- //pushes towards s that increase flow[e] are not allowed
- min_dist = Min(min_dist,dist[target(e)]);
-
-
- if ((target(e) == v) && (flow[e] > 0))
- min_dist = Min(min_dist,dist[source(e)]);
- }
- if (min_dist != Infinity) min_dist++;
- dist[v] = min_dist;
-
- } // else
-
- U.push(v);
- G.init_adj_iterator(v);
-
- } // if (excess[v] > 0)
-
- } // while (!U.empty())
-
-
-
- //code to verify that flow is legal
-
- /*
-
- real tot_s_flow = 0;
- forall_adj_edges(e,s)
- if (source(e) == s) tot_s_flow += cap[e];
- if (tot_s_flow != (excess[s] + excess[t]))
- { cout << "gt_max_flow: total out cap s != excess[s] + excess[t]\n";
- forall_nodes(v,G)
- if ((excess[v] != 0) && (v != t) && (v != s))
- cout << "gt_max_flow: v!=s,t has excess[v]=" << excess[v] << "\n";
- }
-
- */
-
- G.make_directed();
-
- heuristic = num_relabels;
-
- real result = excess[t]; //returns value of maximum flow from s to t
-
- return result;
-
- } // procedure gt_max_flow
-
-
- //procedure to perform backward bfs starting at vertex s_vert with
- //distance label dist_s_vert
-
- static
- void gt_bfs1(node s_vert, int dist_s_vert,
- const graph& G, node s, const edge_array(real)& cap,
- edge_array(real)& flow, node_array(int)& dist)
- {
- node x,y;
- edge e;
- list(node) bfs_Q;
- real c;
-
- dist[s_vert] = dist_s_vert;
- bfs_Q.append(s_vert);
- while (x = bfs_Q.pop())
- {
- forall_adj_edges(e,x)
- {
- if (x == source(e))
- { y = target(e);
- c = flow[e]; }
- else
- { y = source(e);
- c = cap[e] - flow[e]; }
-
- if ( c > 0 && dist[y] == Infinity
- && !(x == target(e) && (s_vert == s)) )
- // while doing bfs with s_vert==s,
- // only edges with flow[e]>0 are reachable from s
-
- { dist[y] = dist[x] + 1;
- bfs_Q.append(y);
- G.init_adj_iterator(y);
-
- //next statement is not really needed, but is added for
- //protection, to ensure that s does not get relabelled by
- //bfs starting at t; this may lead to decrease in d[v]!
- if (y == s) dist[y] = G.number_of_nodes();
- }
-
- } //forall(e,...)
-
- } //while(x == bfs_Q.pop())
-
- } //end procedure gt_bfs1
-
-
- #endif
-