示例#1
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            var solution = new MaxTimeSolution(problem.Size);

            // keep placing customer until none are left.
            var customers = new List <int>(problem.Customers);

            customers.RemoveAt(0);

            double max = problem.Max.Value - (problem.Max.Value * _deltaPercentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs      = new BinaryHeapInsertionCosts();
            double          percentage = _thresholdPercentage;

            while (customers.Count > 0)
            {
                //// try and distribute the remaining customers if there are only a few left.
                //if (customers.Count < problem.Size * percentage)
                //{
                //    bool succes = true;
                //    while (succes && customers.Count > 0)
                //    {
                //        succes = false;
                //        CheapestInsertionResult best = new CheapestInsertionResult();
                //        best.Increase = float.MaxValue;
                //        int best_idx = -1;
                //        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                //        {
                //            IRoute route = solution.Route(route_idx);
                //            CheapestInsertionResult result =
                //                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                //            if (best.Increase > result.Increase)
                //            {
                //                best = result;
                //                best_idx = route_idx;
                //            }
                //        }

                //        IRoute best_route = solution.Route(best_idx);
                //        double route_time = problem.Time(best_route);
                //        if (route_time + best.Increase < max)
                //        { // insert the customer.
                //            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                //            customers.Remove(best.Customer);

                //            this.Improve(problem, solution, max, best_idx);

                //            succes = true;
                //        }
                //    }
                //}

                // select a customer using some heuristic.
                int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                customers.Remove(customer);

                // start a route r.
                IRoute currentRoute = solution.Add(customer);
                solution[solution.Count - 1] = 0;

                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result;
                    if (_useSeedCost)
                    { // use the seed cost; the cost to the seed customer.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers,
                                                                                customer, 0.7);

                        // calculate the 'real' increase.
                        result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                           problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                          problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                    }
                    else
                    { // just use cheapest insertion.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, costs);
                    }

                    // calculate the new weight.
                    solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                    double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                 result.Increase);
                    // cram as many customers into one route as possible.
                    if (potentialWeight < max)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        currentRoute.InsertAfter(result.CustomerBefore, result.Customer);

                        // free some memory in the costs list.
                        costs.Remove(result.CustomerBefore, result.CustomerAfter);

                        // update the cost of the route.
                        solution[solution.Count - 1] = potentialWeight;

                        // improve if needed.
                        if (((problem.Size - customers.Count) % _k) == 0)
                        { // an improvement is decided.
                            // apply the inter-route improvements.
                            var copy = (solution.Clone() as MaxTimeSolution);

                            int countBefore = solution.Route(solution.Count - 1).Count;

                            solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                                                                  solution.Route(solution.Count - 1), solution[solution.Count - 1]);
                            if (!solution.IsValid())
                            {
                                throw new Exception();
                            }
                            int countAfter = solution.Route(solution.Count - 1).Count;
                            if (countAfter != countBefore)
                            {
                                throw new Exception();
                            }

                            // also to the inter-improvements.
                            currentRoute = this.Improve(problem, solution, max, solution.Count - 1);
                        }
                    }
                    else
                    {// ok we are done!
                        this.Improve(problem, solution, max, solution.Count - 1);

                        // break the route.
                        break;
                    }
                }
            }

            // remove empty routes.
            for (int routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--)
            {
                if (solution.Route(routeIdx).IsEmpty)
                {
                    solution.Remove(routeIdx);
                }
            }

            return(solution);
        }
        /// <summary>
        /// Calculates a solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            double max = problem.Max.Value;

            // keep placing customer until none are left.
            List<int> customers = new List<int>(problem.Customers);

            // create n routes.
            for (int customer = 0; customer < customers.Count; customer++)
            {
                solution.Add(customer);
                solution[solution.Count - 1] = calculator.CalculateOneRouteIncrease(
                    0, 0);
            }

            // creates a result.
            MergeResult result = new MergeResult();
            result.Weight = double.MaxValue;

            // loop over all route pairs and merge the smallest merge.
            while (result != null)
            { // keep looping until there is no result anymore.
                result = new MergeResult();
                result.Weight = double.MaxValue;

                for (int route1_idx = 1; route1_idx < solution.Count; route1_idx++)
                { // keep looping over all routes.
                    for (int route2_idx = 0; route2_idx < solution.Count; route2_idx++)
                    { // keep looping over all routes.
                        if (route1_idx == route2_idx)
                        { // only consider different routes.
                            break;
                        }

                        // calculate the merge result.
                        MergeResult current_result = this.TryMerge(problem, solution,
                            route1_idx, route2_idx, problem.Max.Value);

                        // evaluate the current result.
                        if (current_result != null && current_result.Weight < result.Weight)
                        { // current result is best.
                            result = current_result;
                        }
                    }
                }

                // evaluate the result.
                if (result.Weight < double.MaxValue)
                { // there is a result; apply it!
                    IRoute source = solution.Route(result.RouteSourceId);
                    IRoute target = solution.Route(result.RouteTargetId);

                    //string source_string = source.ToString();
                    //string target_string = target.ToString();

                    if (target.Count > 1 && target.First == target.GetNeigbours(result.CustomerTargetSource)[0])
                    {
                        //throw new Exception();
                    }

                    // create an enumeration of all customers of source in the correct order.
                    IEnumerable<int> source_between = new List<int>(
                        source.Between(result.CustomerSourceSource, result.CustomerSourceTarget));

                    // insert after the complete source.
                    int previous = result.CustomerTargetSource;
                    int next = target.GetNeigbours(result.CustomerTargetSource)[0];
                    foreach (int source_customer in source_between)
                    {
                        // insert.
                        target.ReplaceEdgeFrom(previous, source_customer);

                        previous = source_customer; // update previous.
                    }
                    target.ReplaceEdgeFrom(previous, next);

                    // remove the source route.
                    solution.Remove(result.RouteSourceId);
                    solution.RemoveWeight(result.RouteTargetId);

                    // calculate the weight of the new route.
                    solution[result.RouteTargetId] = solution[result.RouteTargetId] + result.Weight +
                        solution[result.RouteSourceId];

                    if (!solution.IsValid())
                    {
                        throw new Exception();
                    }
                }
                else
                { // set the result null.
                    result = null;
                }
            }

            return solution;
        }
示例#3
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            double max = problem.Max.Value - (problem.Max.Value * _delta_percentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs      = new BinaryHeapInsertionCosts();
            double          percentage = _threshold_percentage;

            while (customers.Count > 0)
            {
                // try and distribute the remaining customers if there are only a few left.
                if (customers.Count < problem.Size * percentage)
                {
                    bool succes = true;
                    while (succes && customers.Count > 0)
                    {
                        succes = false;
                        CheapestInsertionResult best = new CheapestInsertionResult();
                        best.Increase = float.MaxValue;
                        int best_idx = -1;
                        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        {
                            IRoute route = solution.Route(route_idx);
                            CheapestInsertionResult result =
                                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                            if (best.Increase > result.Increase)
                            {
                                best     = result;
                                best_idx = route_idx;
                            }
                        }

                        IRoute best_route = solution.Route(best_idx);
                        double route_time = problem.Time(best_route);
                        if (route_time + best.Increase < max)
                        { // insert the customer.
                            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                            customers.Remove(best.Customer);

                            this.Improve(problem, solution, max, best_idx);

                            succes = true;
                        }
                    }
                }

                // select a customer using some heuristic.
                if (customers.Count > 0)
                {
                    // select a customer using some heuristic.
                    int customer = -1;
                    if (_use_seed)
                    { // use a seeding heuristic.
                        customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                    }
                    else
                    { // just select a random customer.
                        customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    }
                    customers.Remove(customer);

                    // start a route r.
                    IRoute current_route = solution.Add(customer);
                    solution[solution.Count - 1] = 0;

                    while (customers.Count > 0)
                    {
                        //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!",
                        //    customers.Count, problem.Size);

                        // calculate the best placement.
                        CheapestInsertionResult result;
                        if (_use_seed_cost)
                        { // use the seed cost; the cost to the seed customer.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers,
                                                                                    customer, _lambda);

                            // calculate the 'real' increase.
                            result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                               problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                              problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                        }
                        else
                        { // just use cheapest insertion.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs);
                        }

                        // calculate the new weight.
                        solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                        double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                      result.Increase);
                        // cram as many customers into one route as possible.
                        if (potential_weight < max)
                        {
                            // insert the customer, it is
                            customers.Remove(result.Customer);
                            current_route.InsertAfter(result.CustomerBefore, result.Customer);

                            // free some memory in the costs list.
                            costs.Remove(result.CustomerBefore, result.CustomerAfter);

                            // update the cost of the route.
                            solution[solution.Count - 1] = potential_weight;

                            // improve if needed.
                            if (((problem.Size - customers.Count) % _k) == 0)
                            { // an improvement is descided.
                                // apply the inter-route improvements.
                                int count_before = solution.Route(solution.Count - 1).Count;

                                solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                                                                      current_route, solution[solution.Count - 1]);
                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                int count_after = solution.Route(solution.Count - 1).Count;

                                // also to the inter-improvements.
                                current_route = this.Improve(problem, solution, max, solution.Count - 1);
                            }
                        }
                        else
                        {// ok we are done!
                            this.Improve(problem, solution, max, solution.Count - 1);

                            // break the route.
                            break;
                        }
                    }
                    //else
                    //{// ok we are done!
                    //    solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                    //        current_route, solution[solution.Count - 1]);

                    //    if (!solution.IsValid())
                    //    {
                    //        throw new Exception();
                    //    }
                    //    int count_after = solution.Route(solution.Count - 1).Count;

                    //    this.Improve(problem, solution, max, solution.Count - 1);

                    //    // break the route.
                    //    break;
                    //}
                }
            }

            // remove empty routes.
            for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--)
            {
                if (solution.Route(route_idx).IsEmpty)
                {
                    solution.Remove(route_idx);
                }
            }

            return(solution);
        }
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            // keep placing customer until none are left.
            List<int> customers = new List<int>(problem.Customers);

            double max = problem.Max.Value - (problem.Max.Value * _delta_percentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();
            double percentage = _threshold_percentage;
            while (customers.Count > 0)
            {
                // try and distribute the remaining customers if there are only a few left.
                if (customers.Count < problem.Size * percentage)
                {
                    bool succes = true;
                    while (succes && customers.Count > 0)
                    {
                        succes = false;
                        CheapestInsertionResult best = new CheapestInsertionResult();
                        best.Increase = float.MaxValue;
                        int best_idx = -1;
                        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                        {
                            IRoute route = solution.Route(route_idx);
                            CheapestInsertionResult result =
                                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                            if (best.Increase > result.Increase)
                            {
                                best = result;
                                best_idx = route_idx;
                            }
                        }

                        IRoute best_route = solution.Route(best_idx);
                        double route_time = problem.Time(best_route);
                        if (route_time + best.Increase < max)
                        { // insert the customer.
                            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                            customers.Remove(best.Customer);

                            this.Improve(problem, solution, max, best_idx);

                            succes = true;
                        }
                    }
                }

                // select a customer using some heuristic.
                if (customers.Count > 0)
                {
                    // select a customer using some heuristic.
                    int customer = -1;
                    if (_use_seed)
                    { // use a seeding heuristic.
                        customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                    }
                    else
                    { // just select a random customer.
                        customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    }
                    customers.Remove(customer);

                    // start a route r.
                    IRoute current_route = solution.Add(customer);
                    solution[solution.Count - 1] = 0;

                    while (customers.Count > 0)
                    {
                        //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!",
                        //    customers.Count, problem.Size);

                        // calculate the best placement.
                        CheapestInsertionResult result;
                        if (_use_seed_cost)
                        { // use the seed cost; the cost to the seed customer.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers,
                                customer, _lambda);

                            // calculate the 'real' increase.
                            result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                                problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                                problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                        }
                        else
                        { // just use cheapest insertion.
                            result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs);
                        }

                        // calculate the new weight.
                        solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                        double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                            result.Increase);
                        // cram as many customers into one route as possible.
                        if (potential_weight < max)
                        {
                            // insert the customer, it is
                            customers.Remove(result.Customer);
                            current_route.InsertAfter(result.CustomerBefore, result.Customer);

                            // free some memory in the costs list.
                            costs.Remove(result.CustomerBefore, result.CustomerAfter);

                            // update the cost of the route.
                            solution[solution.Count - 1] = potential_weight;

                            // improve if needed.
                            if (((problem.Size - customers.Count) % _k) == 0)
                            { // an improvement is descided.
                                // apply the inter-route improvements.
                                int count_before = solution.Route(solution.Count - 1).Count;

                                solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                    current_route, solution[solution.Count - 1]);
                                if (!solution.IsValid())
                                {
                                    throw new Exception();
                                }
                                int count_after = solution.Route(solution.Count - 1).Count;

                                // also to the inter-improvements.
                                current_route = this.Improve(problem, solution, max, solution.Count - 1);
                            }
                        }
                        else
                        {// ok we are done!
                            this.Improve(problem, solution, max, solution.Count - 1);

                            // break the route.
                            break;
                        }
                    }
                    //else
                    //{// ok we are done!
                    //    solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                    //        current_route, solution[solution.Count - 1]);

                    //    if (!solution.IsValid())
                    //    {
                    //        throw new Exception();
                    //    }
                    //    int count_after = solution.Route(solution.Count - 1).Count;

                    //    this.Improve(problem, solution, max, solution.Count - 1);

                    //    // break the route.
                    //    break;
                    //}
                }
            }

            // remove empty routes.
            for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--)
            {
                if (solution.Route(route_idx).IsEmpty)
                {
                    solution.Remove(route_idx);
                }
            }

            return solution;
        }
示例#5
0
        /// <summary>
        /// Calculates a solution.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the calculator.
            MaxTimeCalculator calculator = new MaxTimeCalculator(problem);

            // create the solution.
            MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true);

            double max = problem.Max.Value;

            // keep placing customer until none are left.
            List <int> customers = new List <int>(problem.Customers);

            // create n routes.
            for (int customer = 0; customer < customers.Count; customer++)
            {
                solution.Add(customer);
                solution[solution.Count - 1] = calculator.CalculateOneRouteIncrease(
                    0, 0);
            }

            // creates a result.
            MergeResult result = new MergeResult();

            result.Weight = double.MaxValue;

            // loop over all route pairs and merge the smallest merge.
            while (result != null)
            { // keep looping until there is no result anymore.
                result        = new MergeResult();
                result.Weight = double.MaxValue;

                for (int route1_idx = 1; route1_idx < solution.Count; route1_idx++)
                {         // keep looping over all routes.
                    for (int route2_idx = 0; route2_idx < solution.Count; route2_idx++)
                    {     // keep looping over all routes.
                        if (route1_idx == route2_idx)
                        { // only consider different routes.
                            break;
                        }

                        // calculate the merge result.
                        MergeResult current_result = this.TryMerge(problem, solution,
                                                                   route1_idx, route2_idx, problem.Max.Value);

                        // evaluate the current result.
                        if (current_result != null && current_result.Weight < result.Weight)
                        { // current result is best.
                            result = current_result;
                        }
                    }
                }

                // evaluate the result.
                if (result.Weight < double.MaxValue)
                { // there is a result; apply it!
                    IRoute source = solution.Route(result.RouteSourceId);
                    IRoute target = solution.Route(result.RouteTargetId);

                    //string source_string = source.ToString();
                    //string target_string = target.ToString();

                    if (target.Count > 1 && target.First == target.GetNeigbours(result.CustomerTargetSource)[0])
                    {
                        //throw new Exception();
                    }

                    // create an enumeration of all customers of source in the correct order.
                    IEnumerable <int> source_between = new List <int>(
                        source.Between(result.CustomerSourceSource, result.CustomerSourceTarget));

                    // insert after the complete source.
                    int previous = result.CustomerTargetSource;
                    int next     = target.GetNeigbours(result.CustomerTargetSource)[0];
                    foreach (int source_customer in source_between)
                    {
                        // insert.
                        target.ReplaceEdgeFrom(previous, source_customer);

                        previous = source_customer; // update previous.
                    }
                    target.ReplaceEdgeFrom(previous, next);

                    // remove the source route.
                    solution.Remove(result.RouteSourceId);
                    solution.RemoveWeight(result.RouteTargetId);

                    // calculate the weight of the new route.
                    solution[result.RouteTargetId] = solution[result.RouteTargetId] + result.Weight +
                                                     solution[result.RouteSourceId];

                    if (!solution.IsValid())
                    {
                        throw new Exception();
                    }
                }
                else
                { // set the result null.
                    result = null;
                }
            }

            return(solution);
        }
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            var solution = new MaxTimeSolution(problem.Size);

            // keep placing customer until none are left.
            var customers = new List<int>(problem.Customers);
            customers.RemoveAt(0);

            double max = problem.Max.Value - (problem.Max.Value * _deltaPercentage);

            // keep a list of cheapest insertions.
            IInsertionCosts costs = new BinaryHeapInsertionCosts();
            //            double percentage = _thresholdPercentage;
            while (customers.Count > 0)
            {
                //// try and distribute the remaining customers if there are only a few left.
                //if (customers.Count < problem.Size * percentage)
                //{
                //    bool succes = true;
                //    while (succes && customers.Count > 0)
                //    {
                //        succes = false;
                //        CheapestInsertionResult best = new CheapestInsertionResult();
                //        best.Increase = float.MaxValue;
                //        int best_idx = -1;
                //        for (int route_idx = 0; route_idx < solution.Count; route_idx++)
                //        {
                //            IRoute route = solution.Route(route_idx);
                //            CheapestInsertionResult result =
                //                CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers);
                //            if (best.Increase > result.Increase)
                //            {
                //                best = result;
                //                best_idx = route_idx;
                //            }
                //        }

                //        IRoute best_route = solution.Route(best_idx);
                //        double route_time = problem.Time(best_route);
                //        if (route_time + best.Increase < max)
                //        { // insert the customer.
                //            best_route.InsertAfter(best.CustomerBefore, best.Customer);
                //            customers.Remove(best.Customer);

                //            this.Improve(problem, solution, max, best_idx);

                //            succes = true;
                //        }
                //    }
                //}

                // select a customer using some heuristic.
                int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                customers.Remove(customer);

                // start a route r.
                IRoute currentRoute = solution.Add(customer);
                solution[solution.Count - 1] = 0;

                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result;
                    if (_useSeedCost)
                    { // use the seed cost; the cost to the seed customer.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers,
                            customer, 0.7);

                        // calculate the 'real' increase.
                        result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] +
                            problem.WeightMatrix[result.Customer][result.CustomerAfter]) -
                            problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter];
                    }
                    else
                    { // just use cheapest insertion.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, costs);
                    }

                    // calculate the new weight.
                    solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                    double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                        result.Increase);
                    // cram as many customers into one route as possible.
                    if (potentialWeight < max)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        currentRoute.InsertAfter(result.CustomerBefore, result.Customer);

                        // free some memory in the costs list.
                        costs.Remove(result.CustomerBefore, result.CustomerAfter);

                        // update the cost of the route.
                        solution[solution.Count - 1] = potentialWeight;

                        // improve if needed.
                        if (((problem.Size - customers.Count) % _k) == 0)
                        { // an improvement is decided.
                            // apply the inter-route improvements.
            //                            var copy = (solution.Clone() as MaxTimeSolution);

                            int countBefore = solution.Route(solution.Count - 1).Count;

                            solution[solution.Count - 1] = this.ImproveIntraRoute(problem,
                                solution.Route(solution.Count - 1), solution[solution.Count - 1]);
                            if (!solution.IsValid())
                            {
                                throw new Exception();
                            }
                            int countAfter = solution.Route(solution.Count - 1).Count;
                            if (countAfter != countBefore)
                            {
                                throw new Exception();
                            }

                            // also to the inter-improvements.
                            currentRoute = this.Improve(problem, solution, max, solution.Count - 1);
                        }
                    }
                    else
                    {// ok we are done!
                        this.Improve(problem, solution, max, solution.Count - 1);

                        // break the route.
                        break;
                    }
                }
            }

            // remove empty routes.
            for (int routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--)
            {
                if (solution.Route(routeIdx).IsEmpty)
                {
                    solution.Remove(routeIdx);
                }
            }

            return solution;
        }