Dynamic Programming – Coin Change Problem in Python
Update 2011/02/25 12:07
Updated the code such that it doesn’t rely on a coin of denomination one.
I assisted in hosting the UCSB Programming Competition again this year. Doing so rekindled my love for dynamic programming algorithms, thus why I prepared an example similar to this one for my class and why I wrote this post.
In my own words, dynamic programming is a technique to solve a problem in which previous solutions are used in the computation of later solutions. The generic coin change problem is, given coins of a specified denomination and a number N what are minimum number of coins needed to make change for N? If you don’t like my definitions see wikipedia for dynamic programming and coin problem.
You might be asking yourself, why is this even difficult; don’t I always just take the largest coin possible, as is done when making change with US coins? You’re right, that approach works with US coins and this approach is called a greedy approach. However, if the coins are of value 1, 3, and 4 then the greedy approach would say the best way to make change of 6 is with three coins: 4, 1 and 1. As you’ve probably figured out the correct, or optimal solution is with two coins: 3 and 3.
As I’m very fond of python I coded up a solution which should work in any circumstance so long as 1 is one of the coin denominations. The solution works as follows: Calculate the minimum number of coins to make 1, 2, 3, …, all the way up to the number we want to make change for. At any given point, i, the minimum number of coins to make i is dependent upon previous solutions.
I’m going to be kind of lazy and not actually explain the process as the code is pretty self explanatory, with one addition: The code doesn’t just calculate the minimum number of coins, but rather calculates what coins were used to make the minimum at each point. See the code below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #!/usr/bin/env python import os, sys def solve_coin_change(coins, value): """A dynamic solution to the coin change problem""" table = [None for x in range(value + 1)] table[0] = [] for i in range(1, value + 1): for coin in coins: if coin > i: continue elif not table[i] or len(table[i - coin]) + 1 < len(table[i]): if table[i - coin] != None: table[i] = table[i - coin][:] table[i].append(coin) if table[-1] != None: print '%d coins: %s' % (len(table[-1]), table[-1]) else: print 'No solution possible' if __name__ == '__main__': def usage(): sys.stderr.write('Usage: %s value\n' % os.path.basename(sys.argv[0])) sys.exit(1) # Modify this to alter the denominations of coins coins = [1, 3, 4] if len(sys.argv) != 2: usage() try: value = int(sys.argv[1]) except ValueError: usage() solve_coin_change(coins, value) |
Related Entries
Comments
Comment from Bryce Boe
Time 2011/02/25 at 10:25 AM
The algorithm may not come to a solution if 1 is not a coin value, however, it will always come to a solution if 1 is one of the coin values. For instance if you want to make change for 15 and only have coins of even values then a solution is not possible.
Comment from Bryce Boe
Time 2011/02/25 at 12:14 PM
Actually, Hudson, you were correct. I updated the code so it now works as it previously should have, e.g., it no longer requires a coin of denomination 1. In the event a solution isn’t possible, it outputs no solution possible.
Comment from Hudson
Time 2011/02/25 at 12:26 PM
Comment from Mike
Time 2011/06/30 at 10:24 PM
Do you think you’d be able to write a version for C++?
Comment from Bryce Boe
Time 2011/06/30 at 11:29 PM
While I definitely could, I will pass on that. You can replace the python lists with a dynamic array (new int[size]) in C++ and rather than initializing the values to None, you can use -1. The remainder of the code is almost a direct translation. Good luck!
Comment from Chris
Time 2011/08/03 at 7:32 PM
what changes to the above code be made if the number of coins of each denomination is finite ? for example, we have ten pennies, a dozen dimes and nickles , twenty quarters ?
Comment from Bryce Boe
Time 2011/08/03 at 8:02 PM
@Chris- If I’m not mistaken, the basic algorithm is the same. However, rather than using a list containing denominations (which should really be a set as they should be unique), you would need to have a list containing all the available coins. At each “step” in the solving process, you would need to subtract the used coins from the available coin list.
The may be a more efficient way to do this.
Comment from Hudson
Time 2011/02/25 at 9:55 AM
So If there are no coin “one” in entry of coins, doesn’t work?