You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

170 lines
5.9 KiB

/* maxflow.c */
/* Written by Andrew Makhorin <mao@gnu.org>, October 2015. */
#include <math.h>
#include <glpk.h>
#include "maxflow.h"
#include "misc.h"
/***********************************************************************
* NAME
*
* max_flow - find max flow in undirected capacitated network
*
* SYNOPSIS
*
* #include "maxflow.h"
* int max_flow(int nn, int ne, const int beg[], const int end[],
* const int cap[], int s, int t, int x[]);
*
* DESCRIPTION
*
* This routine finds max flow in a given undirected network.
*
* The undirected capacitated network is specified by the parameters
* nn, ne, beg, end, and cap. The parameter nn specifies the number of
* vertices (nodes), nn >= 2, and the parameter ne specifies the number
* of edges, ne >= 0. The network edges are specified by triplets
* (beg[k], end[k], cap[k]) for k = 1, ..., ne, where beg[k] < end[k]
* are numbers of the first and second nodes of k-th edge, and
* cap[k] > 0 is a capacity of k-th edge. Loops and multiple edges are
* not allowed.
*
* The parameter s is the number of a source node, and the parameter t
* is the number of a sink node, s != t.
*
* On exit the routine computes elementary flows thru edges and stores
* their values to locations x[1], ..., x[ne]. Positive value of x[k]
* means that the elementary flow goes from node beg[k] to node end[k],
* and negative value means that the flow goes in opposite direction.
*
* RETURNS
*
* The routine returns the total maximum flow through the network. */
int max_flow(int nn, int ne, const int beg[/*1+ne*/],
const int end[/*1+ne*/], const int cap[/*1+ne*/], int s, int t,
int x[/*1+ne*/])
{ int k;
/* sanity checks */
xassert(nn >= 2);
xassert(ne >= 0);
xassert(1 <= s && s <= nn);
xassert(1 <= t && t <= nn);
xassert(s != t);
for (k = 1; k <= ne; k++)
{ xassert(1 <= beg[k] && beg[k] < end[k] && end[k] <= nn);
xassert(cap[k] > 0);
}
/* find max flow */
return max_flow_lp(nn, ne, beg, end, cap, s, t, x);
}
/***********************************************************************
* NAME
*
* max_flow_lp - find max flow with simplex method
*
* SYNOPSIS
*
* #include "maxflow.h"
* int max_flow_lp(int nn, int ne, const int beg[], const int end[],
* const int cap[], int s, int t, int x[]);
*
* DESCRIPTION
*
* This routine finds max flow in a given undirected network with the
* simplex method.
*
* Parameters of this routine have the same meaning as for the routine
* max_flow (see above).
*
* RETURNS
*
* The routine returns the total maximum flow through the network. */
int max_flow_lp(int nn, int ne, const int beg[/*1+ne*/],
const int end[/*1+ne*/], const int cap[/*1+ne*/], int s, int t,
int x[/*1+ne*/])
{ glp_prob *lp;
glp_smcp smcp;
int i, k, nz, flow, *rn, *cn;
double temp, *aa;
/* create LP problem instance */
lp = glp_create_prob();
/* create LP rows; i-th row is the conservation condition of the
* flow at i-th node, i = 1, ..., nn */
glp_add_rows(lp, nn);
for (i = 1; i <= nn; i++)
glp_set_row_bnds(lp, i, GLP_FX, 0.0, 0.0);
/* create LP columns; k-th column is the elementary flow thru
* k-th edge, k = 1, ..., ne; the last column with the number
* ne+1 is the total flow through the network, which goes along
* a dummy feedback edge from the sink to the source */
glp_add_cols(lp, ne+1);
for (k = 1; k <= ne; k++)
{ xassert(cap[k] > 0);
glp_set_col_bnds(lp, k, GLP_DB, -cap[k], +cap[k]);
}
glp_set_col_bnds(lp, ne+1, GLP_FR, 0.0, 0.0);
/* build the constraint matrix; structurally this matrix is the
* incidence matrix of the network, so each its column (including
* the last column for the dummy edge) has exactly two non-zero
* entries */
rn = xalloc(1+2*(ne+1), sizeof(int));
cn = xalloc(1+2*(ne+1), sizeof(int));
aa = xalloc(1+2*(ne+1), sizeof(double));
nz = 0;
for (k = 1; k <= ne; k++)
{ /* x[k] > 0 means the elementary flow thru k-th edge goes from
* node beg[k] to node end[k] */
nz++, rn[nz] = beg[k], cn[nz] = k, aa[nz] = -1.0;
nz++, rn[nz] = end[k], cn[nz] = k, aa[nz] = +1.0;
}
/* total flow thru the network goes from the sink to the source
* along the dummy feedback edge */
nz++, rn[nz] = t, cn[nz] = ne+1, aa[nz] = -1.0;
nz++, rn[nz] = s, cn[nz] = ne+1, aa[nz] = +1.0;
/* check the number of non-zero entries */
xassert(nz == 2*(ne+1));
/* load the constraint matrix into the LP problem object */
glp_load_matrix(lp, nz, rn, cn, aa);
xfree(rn);
xfree(cn);
xfree(aa);
/* objective function is the total flow through the network to
* be maximized */
glp_set_obj_dir(lp, GLP_MAX);
glp_set_obj_coef(lp, ne + 1, 1.0);
/* solve LP instance with the (primal) simplex method */
glp_term_out(0);
glp_adv_basis(lp, 0);
glp_term_out(1);
glp_init_smcp(&smcp);
smcp.msg_lev = GLP_MSG_ON;
smcp.out_dly = 5000;
xassert(glp_simplex(lp, &smcp) == 0);
xassert(glp_get_status(lp) == GLP_OPT);
/* obtain optimal elementary flows thru edges of the network */
/* (note that the constraint matrix is unimodular and the data
* are integral, so all elementary flows in basic solution should
* also be integral) */
for (k = 1; k <= ne; k++)
{ temp = glp_get_col_prim(lp, k);
x[k] = (int)floor(temp + .5);
xassert(fabs(x[k] - temp) <= 1e-6);
}
/* obtain the maximum flow thru the original network which is the
* flow thru the dummy feedback edge */
temp = glp_get_col_prim(lp, ne+1);
flow = (int)floor(temp + .5);
xassert(fabs(flow - temp) <= 1e-6);
/* delete LP problem instance */
glp_delete_prob(lp);
/* return to the calling program */
return flow;
}
/* eof */