Coin Change

From Algorithmist
Revision as of 14:05, 27 March 2012 by 199.212.250.155 (Talk)
Jump to: navigation, search

Coin Change is the problem of finding the number of ways of making changes for a particular amount of cents, n, using a given set of denominations d_1 \ldots d_m. It is a general case of Integer Partition, and can be solved with dynamic programming. (The Min-Coin Change is a common variation of this problem.)

Contents

Overview

The problem is typically asked as: If we want to make change for N cents, and we have infinite supply of each of S = \{ S_1, S_2, \ldots, S_m \} valued coins, how many ways can we make the change? (For simplicity's sake, the order does not matter.)

It is more precisely defined as:

Given an integer N and a set of integers S = \{ S_1, S_2, \ldots, S_m \}, how many ways can one express N as a linear combination of S = \{ S_1, S_2, \ldots, S_m \} with non-negative coefficients?

Mathematically, how many solutions are there to N = \sum_{k = 1 \ldots m}{ x_k S_k } where x_k \geq 0, k \in \{ 1 \ldots m \}

For example, for N = 4,S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}.

Other common variations on the problem include decision-based question, such as:

Is there a solution for N = \sum_{k = 1 \ldots m}{ x_k S_k } where x_k \geq 0, k \in \{ 1 \ldots m \} (Is there a solution for integer N and a set of integers S = \{ S_1, S_2, \ldots, S_m \}?)

Is there a solution for N = \sum_{k = 1 \ldots m}{ x_k S_k } where x_k \geq 0, k \in \{ 1 \ldots m \}, \sum_{k = 1 \ldots m}{x_k} \leq T (Is there a solution for integer N and a set of integers S = \{ S_1, S_2, \ldots, S_m \} such that \sum_{k = 1 \ldots m}{x_k} \leq T - using at most T coins)

Recursive Formulation

We are trying to count the number of distinct sets.

Since order does not matter, we will impose that our solutions (sets) are all sorted in non-decreasing order (Thus, we are looking at sorted-set solutions: collections).

For a particular N and S = \{ S_1, S_2, \ldots, S_m \} (now with the restriction that S_1 < S_2 < \ldots < S_m, our solutions can be constructed in non-decreasing order), the set of solutions for this problem, C(N,m), can be partitioned into two sets:

  • There are those sets that does not contain any Sm,
  • Those sets that contain at least 1 Sm,

If a solution does not contain Sm, then we can solve the subproblem of N with S = \{ S_1, S_2, \ldots, S_{m-1} \}, or the solutions of C(N,m - 1).

If a solution does contain Sm, then we are using at least one Sm, thus we are now solving the subproblem of N - Sm, S = \{ S_1, S_2, \ldots, S_m \}. This is C(N - Sm,m).

Thus, we can formulate the following:

C(N,m) = C(N,m - 1) + C(N - Sm,m)

with the base cases:

  • C(N,m) = 1,N = 0
  • C(N,m) = 0,N < 0
  • C( N, m ) = 0, N \geq 1, m \leq 0

Pseudocode

def count( n, m ):
    if n == 0:
        return 1
    if n < 0:
        return 0
    if m <= 0 and n >= 1:
        return 1
 
    return count( n, m - 1 ) + count( n - S[m], m )

Dynamic Programming

Note that the recursion satisfies the weak ordering R(n,m) < R(x,y) \iff n \leq x, m \leq y, (n,m) \ne (x,y). As a result, this satisfies the optimal-substructure property of dynamic programming.

The result can be computed in O(nm) time - the above pseudocode can easily be modified to contain memoization. It can be also rewritten as:

func count( n, m )
  initialize table with base cases

  for i from 0 to n
    for j from 0 to m
      table[ i, j ] = table[ i - S_j, j ] + table[ i, j - 1 ]

  return table[ n, m ]
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox