/// <summary>
        /// Obtém a solução do problema a partir das variáveis de compatibilidade.
        /// </summary>
        /// <param name="resultCosts">Os custos por componente.</param>
        /// <param name="variables">A lista das variáveis escolhidas.</param>
        /// <param name="costsMatrices">As matrizes de custos.</param>
        /// <returns>A solução.</returns>
        private GreedyAlgSolution <CostsType>[] GetSolution(
            CostsType[] resultCosts,
            List <CoordsElement>[] variables,
            List <ILongSparseMathMatrix <CostsType> > costsMatrices)
        {
            var result = new GreedyAlgSolution <CostsType> [variables.Length];

            for (int i = 0; i < result.Length; ++i)
            {
                var integerSequence = new IntegerSequence();
                integerSequence.Add(0, costsMatrices[i].GetLength(0) - 1);
                var currentVariables = variables[i];
                for (int j = 0; j < currentVariables.Count; ++j)
                {
                    var column = currentVariables[j].Column;
                    integerSequence.Remove(column);
                }

                var algSol = new GreedyAlgSolution <CostsType>(integerSequence);
                algSol.Cost = resultCosts[i];

                result[i] = algSol;
            }

            return(result);
        }
        /// <summary>
        /// Obtém uma solução a partir duma aproximação inicial.
        /// </summary>
        /// <param name="approximateMedians">As medianas.</param>
        /// <param name="costs">Os custos.</param>
        /// <param name="niter">O número máximo melhoramentos a serem aplicados à solução encontrada.</param>
        /// <returns>A solução construída a partir da aproximação.</returns>
        public GreedyAlgSolution <CoeffType> Run(
            CoeffType[] approximateMedians,
            ILongSparseMathMatrix <CoeffType> costs,
            int niter)
        {
            if (approximateMedians == null)
            {
                throw new ArgumentNullException("approximateMedians");
            }
            else if (costs == null)
            {
                throw new ArgumentNullException("costs");
            }
            else if (approximateMedians.Length != costs.GetLength(1))
            {
                throw new ArgumentException("The number of medians must match the number of columns in costs matrix.");
            }
            else
            {
                var settedSolutions      = new IntegerSequence();
                var approximateSolutions = new List <int>();
                var sum = this.coeffsField.AdditiveUnity;
                for (int i = 0; i < approximateMedians.Length; ++i)
                {
                    var currentMedian = approximateMedians[i];
                    if (!this.coeffsField.IsAdditiveUnity(currentMedian))
                    {
                        sum = this.coeffsField.Add(sum, approximateMedians[i]);
                        if (this.converter.CanApplyDirectConversion(currentMedian))
                        {
                            var converted = this.converter.DirectConversion(currentMedian);
                            if (converted == 1)
                            {
                                settedSolutions.Add(i);
                            }
                            else
                            {
                                throw new OdmpProblemException(string.Format(
                                                                   "The median {0} at position {1} of medians array can't be converted to the unity.",
                                                                   currentMedian,
                                                                   i));
                            }
                        }
                        else
                        {
                            approximateSolutions.Add(i);
                        }
                    }
                }

                if (this.converter.CanApplyDirectConversion(sum))
                {
                    var convertedSum = this.converter.DirectConversion(sum);
                    if (convertedSum <= 0 || convertedSum > approximateMedians.Length)
                    {
                        throw new IndexOutOfRangeException(string.Format(
                                                               "The medians sum {0} is out of bounds. It must be between 1 and the number of elements in medians array.",
                                                               convertedSum));
                    }

                    var solutionBoard = new CoeffType[approximateMedians.Length];
                    var marked        = new BitArray(approximateMedians.Length, false);
                    if (settedSolutions.Count == convertedSum)
                    {
                        var result = new GreedyAlgSolution <CoeffType>(settedSolutions);
                        result.Cost = this.ComputeCost(settedSolutions, costs, solutionBoard, marked);
                        return(result);
                    }
                    else
                    {
                        // Partição das mediana em dois conjuntos: as que vão falzer parte da solução e as restantes
                        // entre as soluções aproximadas.
                        var recoveredMedians   = new List <int>();
                        var unrecoveredMedians = new List <int>();
                        var innerComparer      = new InnerComparer(approximateMedians, this.comparer);
                        approximateSolutions.Sort(innerComparer);

                        var count = convertedSum - settedSolutions.Count;
                        var i     = 0;
                        for (; i < count; ++i)
                        {
                            recoveredMedians.Add(approximateSolutions[i]);
                            settedSolutions.Add(approximateSolutions[i]);
                        }

                        for (; i < approximateSolutions.Count; ++i)
                        {
                            unrecoveredMedians.Add(approximateSolutions[i]);
                        }

                        var currentCost = this.ComputeCost(settedSolutions, costs, solutionBoard, marked);

                        // Processa as melhorias de uma forma simples caso seja possível
                        if (unrecoveredMedians.Count > 0 && niter > 0)
                        {
                            var exchangeSolutionBoard = new CoeffType[solutionBoard.Length];
                            var currentBestBoard      = new CoeffType[solutionBoard.Length];
                            for (i = 0; i < niter; ++i)
                            {
                                var itemToExchange          = -1;
                                var itemToExchangeIndex     = -1;
                                var itemToExchangeWith      = -1;
                                var itemToExchangeWithIndex = -1;
                                var minimumCost             = this.coeffsField.AdditiveUnity;
                                for (int j = 0; j < recoveredMedians.Count; ++j)
                                {
                                    for (int k = 0; k < unrecoveredMedians.Count; ++k)
                                    {
                                        var replacementCost = this.ComputeReplacementCost(
                                            unrecoveredMedians[k],
                                            recoveredMedians[j],
                                            settedSolutions,
                                            costs,
                                            solutionBoard,
                                            exchangeSolutionBoard);
                                        if (this.comparer.Compare(replacementCost, minimumCost) < 0)
                                        {
                                            // Aceita a troca
                                            itemToExchange          = recoveredMedians[j];
                                            itemToExchangeIndex     = j;
                                            itemToExchangeWith      = unrecoveredMedians[k];
                                            itemToExchangeWithIndex = k;
                                            minimumCost             = replacementCost;

                                            var swapBestBoard = currentBestBoard;
                                            currentBestBoard      = exchangeSolutionBoard;
                                            exchangeSolutionBoard = swapBestBoard;
                                        }
                                    }
                                }

                                if (itemToExchange == -1 || itemToExchangeWith == -1)
                                {
                                    i = niter - 1;
                                }
                                else
                                {
                                    // Efectua a troca
                                    var swapSolutionBoard = solutionBoard;
                                    solutionBoard    = currentBestBoard;
                                    currentBestBoard = swapSolutionBoard;

                                    currentCost = this.coeffsField.Add(currentCost, minimumCost);
                                    settedSolutions.Remove(itemToExchange);
                                    settedSolutions.Add(itemToExchangeWith);

                                    var swap = recoveredMedians[itemToExchangeIndex];
                                    recoveredMedians[itemToExchangeIndex]       = unrecoveredMedians[itemToExchangeWithIndex];
                                    unrecoveredMedians[itemToExchangeWithIndex] = swap;
                                }
                            }
                        }

                        return(new GreedyAlgSolution <CoeffType>(settedSolutions)
                        {
                            Cost = currentCost
                        });
                    }
                }
                else
                {
                    throw new OdmpProblemException("The sum of medians can't be converted to an integer.");
                }
            }
        }