Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Elementary Algorithms / Arrays and Dynamic Programming

Solves two common unbounded knapsack variants, where each item may be used any number of times. In the maximum-value version, each item has a weight and value, and the goal is to maximize total value subject to a capacity limit. In the coin change version, each coin denomination may be used any number of times, and the goal is to count unordered ways to form a target sum.

For unbounded maximum-value knapsack, weights are iterated in increasing order so the current item may be reused. For unordered coin change, coins are the outer loop so each multiset of coins is counted once, independent of ordering.

  • unbounded_knapsack(weight, value, capacity) returns the maximum value achievable with total weight at most capacity.
  • count_coin_change(coins, target) returns the number of unordered ways to make sum target using the given coin denominations.
  • All capacities must be nonnegative integers. Weights and coin denominations should be positive to avoid infinitely many uses of a zero-weight item.

Implementation

#include <algorithm>
#include <cstdint>
#include <vector>

int64_t unbounded_knapsack(
    const std::vector<int> &weight, const std::vector<int64_t> &value, int capacity
) {
  int n = static_cast<int>(weight.size());
  std::vector<int64_t> dp(capacity + 1, 0);
  for (int i = 0; i < n; i++) {
    for (int w = weight[i]; w <= capacity; w++) {
      dp[w] = std::max(dp[w], dp[w - weight[i]] + value[i]);
    }
  }
  return dp[capacity];
}

int64_t count_coin_change(const std::vector<int> &coins, int target) {
  std::vector<int64_t> dp(target + 1, 0);
  dp[0] = 1;
  for (int coin : coins) {
    for (int sum = coin; sum <= target; sum++) {
      dp[sum] += dp[sum - coin];
    }
  }
  return dp[target];
}

Example Usage

#include <cassert>
using namespace std;

int main() {
  vector<int> weight{3, 4, 5};
  vector<int64_t> value{4, 5, 7};
  assert(unbounded_knapsack(weight, value, 10) == 14);  // Two weight-5 items.

  vector<int> coins{1, 2, 5};
  assert(count_coin_change(coins, 5) == 4);  // 5, 2+2+1, 2+1+1+1, 1*5.
  return 0;
}