/// <summary> /// Switches the given directed id to the best turn given the before and after directed id's. /// </summary> public static bool SwitchToBestTurn(int directedId, int beforeDirectedId, int afterDirectedId, float[][] weights, float[] turnPenalties, out int betterDirectedId, out bool departureIdSwitched, out bool arrivalIdSwitched, out float delta) { int arrivalId, departureId, turn, id, beforeDepartureOffset, afterArrivalOffset, temp; DirectedHelper.ExtractOffset(DirectedHelper.ExtractTurn(beforeDirectedId), out temp, out beforeDepartureOffset); DirectedHelper.ExtractOffset(DirectedHelper.ExtractTurn(afterDirectedId), out afterArrivalOffset, out temp); DirectedHelper.ExtractAll(directedId, out arrivalId, out departureId, out id, out turn); var bestWeight = float.MaxValue; var bestDirectedId = -1; var previousWeight = float.MaxValue; departureIdSwitched = false; arrivalIdSwitched = false; for (var newBeforeDepartureOffset = 0; newBeforeDepartureOffset < 2; newBeforeDepartureOffset++) { for (var newAfterArrivalOffset = 0; newAfterArrivalOffset < 2; newAfterArrivalOffset++) { for (var i = 0; i < 4; i++) { var newDirectedId = DirectedHelper.BuildDirectedId(id, i); int localTurn; DirectedHelper.ExtractAll(newDirectedId, out arrivalId, out departureId, out id, out localTurn); var newBeforeDirectedId = DirectedHelper.UpdateDepartureOffset(beforeDirectedId, newBeforeDepartureOffset); var newAfterDirectedId = DirectedHelper.UpdateArrivalOffset(afterDirectedId, newAfterArrivalOffset); var newBeforeDepartureId = DirectedHelper.ExtractDepartureId(newBeforeDirectedId); var newAfterArrivalId = DirectedHelper.ExtractArrivalId(newAfterDirectedId); var newBeforeTurn = DirectedHelper.ExtractTurn(newBeforeDirectedId); var newAfterTurn = DirectedHelper.ExtractTurn(newAfterDirectedId); var newWeight = turnPenalties[localTurn]; newWeight += weights[newBeforeDepartureId][arrivalId]; newWeight += weights[departureId][newAfterArrivalId]; newWeight += turnPenalties[newBeforeTurn]; newWeight += turnPenalties[newAfterTurn]; if (i == turn && newBeforeDepartureOffset == beforeDepartureOffset && newAfterArrivalOffset == afterArrivalOffset) { previousWeight = newWeight; } if (bestWeight > newWeight) { bestWeight = newWeight; bestDirectedId = newDirectedId; departureIdSwitched = newBeforeDepartureOffset != beforeDepartureOffset; arrivalIdSwitched = newAfterArrivalOffset != afterArrivalOffset; } } } } delta = previousWeight - bestWeight; betterDirectedId = bestDirectedId; return(betterDirectedId != directedId); }
/// <summary> /// Shifts the directed customer aft er the given directed before with the best possible turns. /// </summary> public static float ShiftAfterBestTurns(this Tour tour, float[][] weights, float[] penalties, int directedCustomer, int directedBefore) { var customer = DirectedHelper.ExtractId(directedCustomer); var directedAfter = tour.GetNeigbour(directedCustomer); if (directedAfter == Constants.NOT_SET) { // TODO: figure out if this happens and if so how to calculate turns. return(0); } // insert directed customer. tour.ShiftAfter(directedCustomer, directedBefore); // calculate best shift-after. int departureOffset1, arrivalOffset3, turn2; var cost = CheapestInsertion.CheapestInsertionDirectedHelper.CalculateCheapestInsert(weights, penalties, directedBefore, customer, directedAfter, !tour.IsFirst(directedBefore), !tour.IsLast(directedAfter), out departureOffset1, out arrivalOffset3, out turn2); var newDirectedBefore = DirectedHelper.UpdateDepartureOffset(directedBefore, departureOffset1); var newDirectedAfter = DirectedHelper.UpdateArrivalOffset(directedAfter, arrivalOffset3); var newDirectedCustomer = DirectedHelper.BuildDirectedId(customer, turn2); if (directedBefore != newDirectedBefore) { tour.Replace(directedBefore, newDirectedBefore); } if (directedCustomer != newDirectedCustomer) { tour.Replace(directedCustomer, newDirectedCustomer); } if (directedAfter != newDirectedAfter) { tour.Replace(directedAfter, newDirectedAfter); } return(cost); }