Project Euler Problem 31 Solution

Project Euler Problem 31 Solution

Coin Sums

by {BetaProjects} | Project Euler & HackerRank

Project Euler Problem 31 Statement

In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:

1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).
It is possible to make £2 in the following way:

1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
How many different ways can £2 be made using any number of coins?

Solution

Project Euler Problem 31 asks us to determine how many ways we can make £2 (200 pence) using any combination of British coins. The coins available are 1p, 2p, 5p, 10p, 20p, 50p, £1 (100p), and £2 (200p). The solution provided is an efficient way to solve this combinatorial problem using dynamic programming. Here's an in-depth breakdown of how it works:

Problem Restatement

The task is to count the number of distinct ways to form a target value (200 pence) using given coin denominations. Each coin can be used any number of times, including zero.

Solution Analysis

The Python solution leverages a concept called dynamic programming (DP), specifically a DP array that records the number of ways to form each possible sum up to the target. Here's how each part of the solution works:

Step 1: Define Target and Coins

target = 200
coins = [1, 2, 5, 10, 20, 50, 100, 200]

Step 2: Initialize Ways Array

ways = [1] + [0]*target

Step 3: Dynamic Programming Iteration Over Each Coin

for coin in coins:
    for i in range(coin, target + 1):
        ways[i] += ways[i - coin]

This section uses nested loops to build up the number of ways to form each value from 1 to target. Let's break down each part:

  1. Outer Loop (for coin in coins):
    • The outer loop iterates over each coin denomination in the coins list. For each coin, we update the ways array to reflect how many additional ways to achieve each sum are possible with this coin.
  2. Inner Loop (for i in range(coin, target + 1)):
    • For each coin, the inner loop iterates from coin to target. This range is chosen because we only need to consider sums that are at least as large as the coin's value (e.g., there's no way to form 5 pence with a 10p coin alone). target+1 is used to include target for consideration
  3. Dynamic Programming Update (ways[i] += ways[i - coin]):
    • For each i, ways[i] is updated by adding ways[i - coin].
      Explanation: ways[i - coin] represents the number of ways to make the value i - coin using the available coins. By adding coin to any way of making i - coin, we obtain a way of making i. Therefore, ways[i] accumulates the count of ways to make i by considering the addition of the current coin denomination.
    • This update step ensures that each ways[i] contains the total number of distinct ways to achieve the sum target after considering all coins up to the current one.

Step 4: Output the Result

print("Ways to make change =", ways[target])
After both loops complete, ways[target] will contain the total number of ways to make 200 pence using the coins in coins. This value is printed as the solution.

Example Walkthrough

Let's go through a smaller example with a target of 5 and coins [1, 2, 5] to clarify how the solution works.

  1. Initialization:
    target = 5
    coins = [1, 2, 5]
    ways = [1, 0, 0, 0, 0, 0]
  2. Processing Coin 1: For each i from 1 to 5, add ways[i - 1] to ways[i]:
    i = 1: ways[1] += ways[0] → ways = [1, 1, 0, 0, 0, 0]
    i = 2: ways[2] += ways[1] → ways = [1, 1, 1, 0, 0, 0]
    i = 3: ways[3] += ways[2] → ways = [1, 1, 1, 1, 0, 0]
    i = 4: ways[4] += ways[3] → ways = [1, 1, 1, 1, 1, 0]
    i = 5: ways[5] += ways[4] → ways = [1, 1, 1, 1, 1, 1]
  3. Processing Coin 2: For each i from 2 to 5, add ways[i - 2] to ways[i]:
    i = 2: ways[2] += ways[0] → ways = [1, 1, 2, 1, 1, 1]
    i = 3: ways[3] += ways[1] → ways = [1, 1, 2, 2, 1, 1]
    i = 4: ways[4] += ways[2] → ways = [1, 1, 2, 2, 3, 1]
    i = 5: ways[5] += ways[3] → ways = [1, 1, 2, 2, 3, 3]
  4. Processing Coin 5: For each i from 5 to 5, add ways[i - 5] to ways[i]:
    i = 5: ways[5] += ways[0] → ways = [1, 1, 2, 2, 3, 4]
    The final value of ways[5] is 4, which means there are four ways to make 5 pence with coins [1, 2, 5]

Complexity and Efficiency

This solution has a time complexity of O(n×m), where n is the target amount and m is the number of coin denominations. This is efficient for problems of this type because each value up to target is computed only once for each coin.

Conclusion

The dynamic programming approach in this solution avoids the need for more complex recursive combinations, making it highly efficient. The ways array efficiently builds up the count of combinations by leveraging previously computed results, providing an elegant solution to the coin-sum problem.

HackerRank version

HackerRank Project Euler 31 changes the target total from £200 to a variable target £1 ≤ N ≤ £105

Python Source Code

target = 200
coins = [1, 2, 5, 10, 20, 50, 100, 200]
ways = [1] + [0]*target

for coin in coins:
    for i in range(coin, target+1):
        ways[i] += ways[i-coin]

print "Ways to make change =", ways[target]	

Last Word