/// <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 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) { if (items.Any() == false) { return Enumerable.Empty<IItem>(); } IList<IItem> itemList = items.ToList(); var valueMatrix = new TwoDimensionalSparseMatrix<long>(); var keepMatrix = new TwoDimensionalSparseMatrix<bool>(); int itemCount = itemList.Count; SolveKnapsackProblem(maxWeight, itemList, valueMatrix, keepMatrix, itemCount); return Package(itemList, keepMatrix, maxWeight); }
/// <summary> /// Packages the specified item list. /// </summary> /// <param name="itemList">The item list.</param> /// <param name="keepMatrix">The keep matrix.</param> /// <param name="maxWeight">The maximum weight.</param> /// <returns>The items packed up into a knapsack</returns> private static IEnumerable<IItem> Package( IList<IItem> itemList, TwoDimensionalSparseMatrix<bool> keepMatrix, long maxWeight) { int itemCount = itemList.Count; var knapsackItems = Enumerable.Empty<IItem>(); long upperBound = maxWeight; for (int i = itemCount; i > 0; i--) { if (keepMatrix[i, upperBound]) { IItem currentItem = itemList[i - 1]; knapsackItems = knapsackItems.Append(currentItem); upperBound -= currentItem.Weight; } } return knapsackItems; }
/// <summary> /// Solves the knapsack problem. /// </summary> /// <param name="maxWeight">The maximum weight.</param> /// <param name="itemList">The item list.</param> /// <param name="valueMatrix">The value matrix.</param> /// <param name="keepMatrix">The keep matrix.</param> /// <param name="itemCount">The item count.</param> private static void SolveKnapsackProblem( long maxWeight, IList<IItem> itemList, TwoDimensionalSparseMatrix<long> valueMatrix, TwoDimensionalSparseMatrix<bool> keepMatrix, int itemCount) { for (var currentFileIndex = 1; currentFileIndex <= itemCount; currentFileIndex++) { var weightAtPreviousIndex = itemList[currentFileIndex - 1].Weight; var valueAtPreviousIndex = itemList[currentFileIndex - 1].Value; for (var currentWeight = 0; currentWeight <= maxWeight; currentWeight++) { var newProspectiveValue = valueAtPreviousIndex + valueMatrix[currentFileIndex - 1, currentWeight - weightAtPreviousIndex]; var oldValue = valueMatrix[currentFileIndex - 1, currentWeight]; if (weightAtPreviousIndex <= currentWeight && newProspectiveValue > oldValue) { valueMatrix[currentFileIndex, currentWeight] = newProspectiveValue; keepMatrix[currentFileIndex, currentWeight] = true; } else { valueMatrix[currentFileIndex, currentWeight] = oldValue; } } } }
/// <summary> /// Packages the specified item list. /// </summary> /// <param name="itemList">The item list.</param> /// <param name="keepMatrix">The keep matrix.</param> /// <param name="maxWeight">The maximum weight.</param> /// <returns>The items packed up into a knapsack</returns> private static IEnumerable<IItem> Package( IList<IItem> itemList, TwoDimensionalSparseMatrix<bool> keepMatrix, long maxWeight) { int itemCount = itemList.Count; var knapsackItems = Enumerable.Empty<IItem>(); long currentWeightToCheck = maxWeight; while(true) { bool foundItem = false; for (int itemIndex = 0; itemIndex < itemList.Count; itemIndex++) { if(keepMatrix[itemIndex, currentWeightToCheck]) { IItem itemToTake = itemList[itemIndex]; knapsackItems = knapsackItems.Append(itemToTake); currentWeightToCheck -= itemToTake.Weight; foundItem = true; break; } } if (foundItem == false) { break; } } return knapsackItems; }
/// <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; } }