function [exitFlag exitMsg netStruct] = ca_minimaxUtilizationLinearCost (netStruct, algorithmParameters, net2planParameters)

	% Algorithm for capacity assignment problems which tries to minimize
	% the maximum link utilization, limited by a maximum network cost budget.
	%
	% The network cost C is the sum of the costs of the links C_e, where
	% the cost in a link grows linearly with capacities:
	% C_e = alpha*u_e + beta*d_e*u_e 
	%
	% It requires CVX solver installed and running.
	%
	% PARAM: alpha | 0 | Linear cost coefficient with capacity (cost per Erlang)
	% PARAM: beta | 1 | Linear cost coefficient with capacity-distance power product (cost per Erlang and km)
	% PARAM: Cmax | 10000 | Maximum network cost 

	%% Sanity checks
	alpha = str2double (algorithmParameters.alpha);
	beta = str2double (algorithmParameters.beta);
	Cmax = str2double (algorithmParameters.Cmax);
	assert(isfinite(alpha) && alpha >= 0, '"alpha" must be greater or equal than zero');
	assert(isfinite(beta) && beta >= 0, '"beta" must be greater or equal than zero');
	assert(isfinite(Cmax) && Cmax > 0, '"Cmax" must be greater than zero');
	
	assert(isfield(netStruct, 'linkTable'), 'A set of links is required');
	assert(isfield(netStruct, 'demandTable'), 'A set of demands is required');
	assert(isfield(netStruct, 'routingMatrix'), 'A valid routing is required');
	assert(isCvxInstalledAndRunning(), 'CVX solver must be installed and running');

	% initialize some variables
	E = size(netStruct.linkTable, 1);
	h_d = netStruct.offeredTrafficInErlangs;
	x_dp = netStruct.routingMatrix;
	delta_pe = seqLinksPerPath2linkOccupancyPerPath(netStruct.pathList, E);
	y_e = trafficPerLink(h_d, x_dp, delta_pe);
	distance_e = netStruct.linkLengthInKm;

	cvx_begin

		cvx_quiet(true);

		variables rho; % Maximum utilization
		variables rho_e(1,E); % Utilization per link (rho_e = y_e / u_e)

		minimize( rho );
		subject to
		
			% In all links, the utilization is below rho
			rho_e <= rho;
			
			% The capacity is enough
			rho_e <= 1;
			% rho <= 1; % This constraint and the previous one are equivalent, so can be removed
			
			% The cost of the network is limited to Cmax
			% sum_e alpha*u_e + beta*d_e*u_e <= Cmax (one constraint)
			sum(inv_pos(rho_e) .* y_e .* (alpha + beta * distance_e)) <= Cmax;
			
			% Non-negativity
			rho_e >= 0;
			% rho >= 0; % This constraint is redundant, so can be removed

	cvx_end

	if strcmp(cvx_status, 'Solved') || strcmp(cvx_status, 'Inaccurate/Solved')
		exitFlag = 0;
		exitMsg = 'OK!';

		netStruct.linkCapacityInErlangs = y_e ./ rho_e;
	else
		exitFlag = -1;
		exitMsg = cvx_status;
		netStruct = [];
	end
		
end
