/// <summary>
 /// Constructor for a candidate solution.
 /// </summary>
 /// <param name="items">List of all the items</param>
 /// <param name="index">index (into the above list) of the last item to be added to this candidate solution</param>
 /// <param name="previous">the remaining items</param>
 public CandidateSolution(List <KnapsackItem> items, int index, CandidateSolution previous)
 {
     if (index == -1)
     {
         _index    = index;
         _value    = 0;
         _weight   = 0;
         _previous = null;
     }
     else
     {
         _index    = index;
         _value    = previous.Value + items[index].Value;
         _weight   = previous.Weight + items[index].Weight;
         _previous = previous;
     }
 }
        /// <summary>
        /// A method to compute the upper bound
        /// </summary>
        /// <param name="toCompute">The candidate solution whose upper bound we wish to compute</param>
        /// <param name="foundSoFar">The best candidate solution we have found so far</param>
        /// <returns>the upper bound</returns>
        public int ComputeBounds(CandidateSolution toCompute, ref CandidateSolution best)
        {
            int i = toCompute.Index + 1;

            while (i < _items.Count && (toCompute.Weight + _items[i].Weight) <= _weightLimit)
            {
                CandidateSolution newSolution = new CandidateSolution(_items, i, toCompute);
                toCompute = newSolution;
                i++;
            }
            if (toCompute.Value > best.Value)
            {
                best = toCompute;
            }
            if (i >= _items.Count || toCompute.Weight == _weightLimit)
            {
                return(toCompute.Value);
            }
            else
            {
                return((int)(((((long)(_weightLimit - toCompute.Weight) * (_items[i].Value)) - 1) / (_items[i].Weight)) + toCompute.Value));
            }
        }
        /// <summary>
        /// Method to find the optimal solution
        /// </summary>
        /// <param name="filename">input file</param>
        public void Solve(string filename)
        {
            _weightLimit = ReadInput(filename);
            CandidateSolution candidate = new CandidateSolution(_items, -1, null);
            CandidateSolution best      = candidate;

            PriorityQueue <int, CandidateSolution> queue = new PriorityQueue <int, CandidateSolution>();

            queue.Add(candidate, ComputeBounds(candidate, ref best));

            while (queue.Count > 0 && queue.MaximumPriority >= best.Value)
            {
                CandidateSolution root = queue.RemoveMaximumPriority();
                int k = root.Index + 1;
                for (int j = k; j < _items.Count; j++)
                {
                    CandidateSolution child = new CandidateSolution(_items, j, root);
                    if (child.Weight <= _weightLimit)
                    {
                        int childBounds = ComputeBounds(child, ref best);
                        if (childBounds > best.Value)
                        {
                            queue.Add(child, childBounds);
                        }
                    }
                }
            }
            _totalValue  = best.Value;
            _totalWeight = best.Weight;
            while (best.Previous != null)
            {
                KnapsackItem tmp = _items[best.Index];
                tmp.SelectionText  = "X";
                _items[best.Index] = tmp;
                best = best.Previous;
            }
        }