/* * Compares node to its parent. * If the node is smaller than its parent they are swapped. * As it sorts this method goes through at most log n levels in the heap. * Therefore the Big-O is O(logn). */ private void BubbleUp(PartialPath node) { while (positions[node] != 1 && node.Priority < Parent(node).Priority) { Swap(node, Parent(node)); } }
/* * Compares node to its two children. * If it is larger than a child, it swaps with the smallest child. * As it sorts this method goes through at most log n levels in the heap. * Therefore the Big-O is O(logn). */ private void SiftDown(PartialPath node) { while (SmallestChild(node) != null && node.Priority > SmallestChild(node).Priority) { Swap(node, SmallestChild(node)); } }
/* * Swaps two nodes in the array. * Also swaps their positions in the positions array (O(1)). */ private void Swap(PartialPath node1, PartialPath node2) { int pos1 = positions[node1]; int pos2 = positions[node2]; nodes[pos1] = node2; nodes[pos2] = node1; positions[node1] = pos2; positions[node2] = pos1; }
/* * Generates all child partial paths. * It creates one for each non-infinte edge * leaving the last city visited. * If the new node's lower bound < bssf, it's added to the queue. */ private void GenerateChildren(PartialPath currentNode, PriorityQueue queue) { for (int i = 1; i < Cities.Length; i++) { if (currentNode.Matrix[currentNode.LastCityVisited, i] != double.PositiveInfinity) { PartialPath child = new PartialPath(currentNode, i); if (child.LowerBound < costOfBssf()) { queue.Insert(child); } } } }
/* * Removes the root node (the minimum). * Replaces the root with the lowest right-most node. * This node is then "sifted" down until the queue is sorted. * O(logn) since it has to go through log n levels in the heap. */ public PartialPath DeleteMin() { PartialPath min = nodes[1]; PartialPath last = nodes[nodes.Count - 1]; positions[last] = 1; positions[min] = -1; nodes.Remove(last); if (!Empty()) { nodes[1] = last; SiftDown(nodes[1]); } return(min); }
/// <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[] bBSolveProblem() { string[] results = new string[3]; int count = 0; Stopwatch timer = new Stopwatch(); PriorityQueue queue = new PriorityQueue(); timer.Start(); greedySolveProblem(); queue.Insert(new PartialPath(CalculateInitialMatrix(), Cities)); /* While there are still partial paths on the queue, * the best one is popped off and its children are generated. * Those that are better than the bssf are added to the queue. */ while (timer.Elapsed.TotalMilliseconds < time_limit && !queue.Empty()) { PartialPath currentNode = queue.DeleteMin(); if (currentNode.FullPath && currentNode.CompletePath) { TSPSolution potentialSolution = new TSPSolution(currentNode.Path); if (potentialSolution.costOfRoute() < costOfBssf()) { bssf = potentialSolution; count++; } } else if (currentNode.LowerBound < costOfBssf()) { GenerateChildren(currentNode, queue); } } timer.Stop(); results[COST] = costOfBssf().ToString(); results[TIME] = timer.Elapsed.ToString(); results[COUNT] = count.ToString(); Console.WriteLine("Branch & Bound Size: " + Cities.Length + " Random: " + Seed + " Path: " + costOfBssf().ToString() + " Time: " + timer.Elapsed.ToString()); return(results); }
/* * Returns the smallest child of a given node. * If the node has no children 0 is returned (O(1)). */ private PartialPath SmallestChild(PartialPath node) { int posFirstChild = positions[node] * 2; int posSecondChild = posFirstChild + 1; if (posFirstChild > nodes.Count - 1) { return(null); //no children } else if (posSecondChild > nodes.Count - 1) { return(nodes[posFirstChild]); //only one child } else { return(nodes[posFirstChild].Priority < nodes[posSecondChild].Priority ? nodes[posFirstChild] : nodes[posSecondChild]); //return whichever child is smaller } }
/* * Constructor used for child nodes. * The data from the parent node is copied. * After this the edge to the next city is added. * During this process the matrix is reduced. * The lower bound is recalculated as well. */ public PartialPath(PartialPath parent, int cityToVisit) { lowerBound = parent.lowerBound; cities = parent.cities; path = new List <int>(); for (int i = 0; i < parent.path.Count; i++) { path.Add(parent.path[i]); } matrix = new double[cities.Length, cities.Length]; for (int i = 0; i < cities.Length; i++) { for (int j = 0; j < cities.Length; j++) { matrix[i, j] = parent.matrix[i, j]; } } AddCity(LastCityVisited, cityToVisit); }
/* * Returns the parent of a given node (O(1)). */ private PartialPath Parent(PartialPath node) { return(nodes[positions[node] / 2]); }
/* * Inserts a node at the lowest right-most spot. * BubbleUp is then called which resorts the queue. * O(logn) since it has to go through log n levels in the heap. */ public void Insert(PartialPath node) { nodes.Add(node); positions.Add(node, nodes.Count - 1); BubbleUp(node); }