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
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							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 */
							 |