//creates a new node given its parent and the index of which city it should follow next
            public bBNode(bBNode parent, int chosen)
            {
                //keep a reference to the list of cities
                this.cities = parent.cities;

                //make deep copies of important data structures
                this.route  = new ArrayList(parent.route.ToArray());
                this.lookup = new ArrayList(parent.lookup.ToArray());
                this.used   = new bool[cities.Length];
                parent.used.CopyTo(this.used, 0);
                this.matrix = parent.matrix.Clone() as double[, ];
                this.bound  = 0;
                bound      += parent.bound;


                //add the next chosen city to the route
                route.Add(cities[chosen]);
                //mark the city as used
                used[chosen] = true;
                //add the index of the city to the lookup array
                lookup.Add(chosen);

                //handle & reduce matrix
                if (route.Count > 1)
                {
                    int prev = (int)lookup[lookup.Count - 2];
                    this.bound          += matrix[prev, chosen];
                    matrix[prev, chosen] = double.PositiveInfinity;
                    matrix[chosen, prev] = double.PositiveInfinity;
                    infiniteRow(prev);
                    infiniteCol(chosen);
                }
                Reduce();
            }
            /**
             * Returns the best node in the queue.
             * Replaces the top node with the last node, bubbles down, and decreases size of queue.
             */
            public bBNode DeleteBestRoute()
            {
                bBNode item = queue[1];

                BubbleDown(queue[count], 1);
                queue[count] = null;
                count--;
                return(item);
            }
 /**
  * Lets a node move up the queue while it has a higher priority than its parent
  */
 private void BubbleUp(bBNode item, int index)
 {
     while (index != 1 && queue[index / 2] < item)
     {
         queue[index] = queue[index / 2];
         queue[index / 2].SetIndex(index);
         index = index / 2;
     }
     queue[index] = item;
     item.SetIndex(index);
 }
 /**
  * Inserts a node into the array at the bottom and lets it bubble up.
  */
 public void Insert(bBNode item)
 {
     item.SetIndex(states);
     states++;
     count++;
     if (count > maxcount)
     {
         maxcount = count;
     }
     BubbleUp(item, count);
 }
            /**
             * returns a list of children nodes
             * each child node adds another unvisited city to its route
             */
            public List <bBNode> Expand()
            {
                List <bBNode> children = new List <bBNode>();

                for (int c = 0; c < cities.Length; c++)
                {
                    if (used[c])
                    {
                        continue;
                    }

                    bBNode child = new bBNode(this, c);
                    children.Add(child);
                }
                return(children);
            }
            /**
             * Lets a node move down the queue while it has a lower priority than its children
             */
            private void BubbleDown(bBNode item, int index)
            {
                int    child_index = MaxChild(index);
                bBNode child_item  = queue[child_index];

                while (child_index != 0 && child_item > item)
                {
                    queue[index] = child_item;
                    child_item.SetIndex(index);
                    index       = child_index;
                    child_index = MaxChild(index);
                    child_item  = queue[child_index];
                }
                queue[index] = item;
                item.SetIndex(index);
            }
 /**
  * Given an index into the queue, this returns the child with the higher priority
  */
 private int MaxChild(int index)
 {
     if (2 * index > count)
     {
         return(0);
     }
     else
     {
         bBNode rh_child = queue[2 * index];
         bBNode lh_child = queue[2 * index + 1];
         if (rh_child > lh_child)
         {
             return(2 * index);
         }
         else
         {
             return(2 * index + 1);
         }
     }
 }
        /// <summary>
        /// performs a Branch and Bound search of the state space of partial tours
        /// stops when time limit expires and uses BSSF as solution
        /// @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)
        public string[] bBSolveProblem()
        {
            // counts the number of bssf updates / solutions found
            int count = 0;

            // counts the number of pruned states
            int pruned = 0;

            // counts the number of total states
            int total_states = 0;

            //container for results
            string[] results = new string[3];

            //priority queue implementation
            HeapQueue myqueue = new HeapQueue();

            Route = new ArrayList();
            Stopwatch timer = new Stopwatch();

            timer.Start();
            Route.Clear();

            //generate greedy bssf as initial guess
            greedySolveProblem();

            //initialize a matrix with all the cities
            bBNode init = new bBNode(GetCities());

            /**
             * Starts at the first city (0).
             * It doesn't matter where we start because we are looking for a "loop" of cities.
             * And we don't want to repeatedly find the same solution by starting at a different city.
             */
            bBNode root = new bBNode(init, 0);
            bBNode next;

            //initialize queue
            myqueue.MakeQueue((int)Math.Pow(Cities.Length, 2), root);
            total_states++;

            //while the queue is not empty and we haven't hit the time limit . . .
            while (!myqueue.IsEmpty() && timer.ElapsedMilliseconds < this.time_limit)
            {
                // take the top node in the queue
                next = (bBNode)myqueue.DeleteBestRoute();
                //if it has a better solution than the bssf, go deeper, otherwise, we prune it.
                if (next.getBound() < bssf.costOfRoute())
                {
                    // check if the route is finished
                    if (next.getRouteLength() == Cities.Length)
                    {
                        //We found a better solution!
                        bssf = new TSPSolution(next.getRoute());
                        count++;
                    }
                    else
                    {
                        // expand the node, and only insert the children that do better than the bssf
                        List <bBNode> children = next.Expand();
                        foreach (bBNode c in children)
                        {
                            total_states++;
                            if (c.getBound() < bssf.costOfRoute())
                            {
                                myqueue.Insert(c);
                            }
                            else
                            {
                                pruned++;
                            }
                        }
                    }
                }
                else
                {
                    pruned++;
                }
            }
            timer.Stop();

            Console.WriteLine("**************************************");
            Console.WriteLine("# cities: " + Cities.Length);
            Console.WriteLine("# seed: " + _seed);
            Console.WriteLine("RunningTime: " + timer.Elapsed);
            Console.WriteLine("Best tour: " + costOfBssf());
            Console.WriteLine("Max stored states: " + myqueue.getMaxStoredStates());
            Console.WriteLine("Number of Solutions: " + count);
            Console.WriteLine("Number total states: " + total_states);
            Console.WriteLine("Total pruned states: " + pruned);

            results[COST]  = costOfBssf().ToString();                         // load results array
            results[TIME]  = timer.Elapsed.ToString();
            results[COUNT] = count.ToString();

            return(results);
        }
 /**
  * Initializes the queue with the size and the first node.
  */
 public void MakeQueue(int size, bBNode start)
 {
     queue = new bBNode[size + 1];
     Insert(start);
 }