private TspState GreedyCalc(TspState state) { var n = state.CostMatrix.GetLength(0); while (!state.IsComplete) { TspState cheapestBranch = null; var cheapestBranchValue = double.PositiveInfinity; for (var toCity = 0; toCity < n; ++toCity) { if (!state.CanVisit(toCity)) { continue; } var testBranch = state.Visit(toCity); if (testBranch.LowerBound >= cheapestBranchValue) { continue; } cheapestBranch = testBranch; cheapestBranchValue = testBranch.LowerBound; } if (cheapestBranch == null) { return(null); } state = cheapestBranch; } return(state); }
/// <summary> /// performs a Branch and Bound search of the state space of partial tours /// stops when time limit expires and uses BSSF as solution /// </summary> /// <returns> /// results array for GUI that contains three ints: cost of solution, time spent to find solution, number of /// solutions found during search (not counting initial BSSF estimate) /// </returns> public string[] BranchBoundSolveProblem() { var results = new string[3]; var timer = new Stopwatch(); Debug.Assert(_cities.Length > 0); var baseState = new TspState(_cities); timer.Start(); var n = _cities.Length; var queue = new FastPriorityQueue <TspState>(n * n * n); baseState = baseState.Visit(0); queue.Enqueue(baseState, baseState.Heuristic()); // The current best complete route var bestState = GreedyCalc(baseState); var upperBound = bestState?.LowerBound ?? double.PositiveInfinity; var stored = 0; var pruned = 0; var maxStates = 0; var updates = 0; while (queue.Count > 0) { if (queue.Count > maxStates) { maxStates = queue.Count; } // Get best state to check based on heuristic. // Runs in O(log n) time. var state = queue.Dequeue(); // Branch for (var toCity = 0; toCity < n; ++toCity) { // If we can't visit the city, no need to consider it if (!state.CanVisit(toCity)) { continue; } var branchState = state.Visit(toCity); // Bound if (branchState.LowerBound < upperBound) { if (branchState.IsComplete) { ++updates; // On a complete instance, no need to add it to the queue. Debug.Assert(branchState.CostMatrix.Cast <double>().All(double.IsPositiveInfinity), "Cost Matrix is not all infinity"); upperBound = branchState.LowerBound; bestState = branchState; continue; } ++stored; if (queue.Count + 5 >= queue.MaxSize) { queue.Resize(queue.MaxSize * 2); } // Runs in O(log n) time queue.Enqueue(branchState, branchState.Heuristic()); } else { ++pruned; } } // Abandon ship and give the best result otherwise if (timer.ElapsedMilliseconds > _timeLimit) { break; } } timer.Stop(); Debug.Assert(bestState != null && bestState.IsComplete); _bssf = StateToSolution(bestState); results[Cost] = CostOfBssf().ToString(CultureInfo.InvariantCulture); // load results array results[Time] = timer.Elapsed.ToString(); results[Count] = $"{maxStates}/{updates}/{stored}/{pruned}"; return(results); }