/// <summary>
        /// Solves the Knapsack problem
        /// </summary>
        /// <param name="items">The items to put into the knapsack</param>
        /// <param name="maxWeight">The maximum weight the knapsack can hold</param>
        /// <returns>
        /// The items to put into the knapsack
        /// </returns>
        public IEnumerable<IItem> Solve(IEnumerable<IItem> items, long maxWeight)
        {
            IList<IItem> itemList = items.ToList();

            var smallerSolutionList = new OneDimensionalSparseArray<long>();
            var intermediateSolution = new OneDimensionalSparseArray<long>();
            var memoList = new OneDimensionalSparseArray<long>();
            var keepMatrix = new TwoDimensionalSparseMatrix<bool>();

            SolveUnboundedKnapsack(maxWeight, itemList, ref smallerSolutionList, ref intermediateSolution, ref memoList, ref keepMatrix);

            return Package(itemList, keepMatrix, maxWeight);
        }
        /// <summary>
        /// Solves the unbounded knapsack.
        /// </summary>
        /// <param name="maxWeight">The maximum weight.</param>
        /// <param name="itemList">The item list.</param>
        /// <param name="smallerSolutionList">The smaller solution list.</param>
        /// <param name="intermediateSolutionList">The intermediate solution list.</param>
        /// <param name="memoList">The memo list.</param>
        /// <param name="keepMatrix">The keep matrix.</param>
        private static void SolveUnboundedKnapsack(
			long maxWeight,
			IList<IItem> itemList,
			ref OneDimensionalSparseArray<long> smallerSolutionList,
			ref OneDimensionalSparseArray<long> intermediateSolutionList,
			ref OneDimensionalSparseArray<long> memoList,
			ref TwoDimensionalSparseMatrix<bool> keepMatrix)
        {
            for (long weight = 1; weight <= maxWeight; weight++)
            {
                for (int itemIndex = 0; itemIndex < itemList.Count; itemIndex++)
                {
                    IItem currentItem = itemList[itemIndex];
                    if (weight >= currentItem.Weight)
                    {
                        smallerSolutionList[itemIndex] = memoList[weight - currentItem.Weight];
                    }
                    else
                    {
                        smallerSolutionList[itemIndex] = 0;
                    }
                }

                for (int itemIndex = 0; itemIndex < itemList.Count; itemIndex++)
                {
                    IItem currentItem = itemList[itemIndex];
                    if (weight >= currentItem.Weight)
                    {
                        intermediateSolutionList[itemIndex] = smallerSolutionList[itemIndex] + currentItem.Value;
                    }
                    else
                    {
                        intermediateSolutionList[itemIndex] = 0;
                    }
                }

                long fileIndexOfMaxValue = 0;
                memoList[weight] = intermediateSolutionList[0];

                for (int itemIndex = 1; itemIndex < itemList.Count; itemIndex++)
                {
                    if (intermediateSolutionList[itemIndex] > memoList[weight])
                    {
                        memoList[weight] = intermediateSolutionList[itemIndex];
                        fileIndexOfMaxValue = itemIndex;
                    }
                }

                keepMatrix[fileIndexOfMaxValue, weight] = true;
            }
        }