Search code examples
pythonrecursiondynamic-programmingnp

trouble understanding the flow of the code snippet


I'm having a terrible time understanding the below code. It computes the number of ways to make amount of money('n') with coins of the available denominations('coins')

def change(n, coins_available, coins_so_far):
    if sum(coins_so_far) == n:
        yield coins_so_far
    elif sum(coins_so_far) > n:
        pass
    elif coins_available == []:
        pass
    else:
        for c in change(n, coins_available[:], coins_so_far+[coins_available[0]]):
            yield c
        for c in change(n, coins_available[1:], coins_so_far):
            yield c

n = 15
coins = [1, 5, 10, 25]

solutions = [s for s in change(n, coins, [])]
for s in solutions:
    print s

output:

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5]
[1, 1, 1, 1, 1, 5, 5]
[1, 1, 1, 1, 1, 10]
[5, 5, 5]
[5, 10]

I understand how the first iteration is resulting in [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] I don't understand how the [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] gets converted to [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5] I believe the 'coins_so_far' will still hold [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] in the second iteration when 'coins_available' holds [5,10,25]

Any help is greatly appreciated. Thanks


Solution

  • In English:

    How to determine the ways to make change(for n cents, using coins in
    coins_available denominations, and which include a pile of coins_so_far):
        If the coins_so_far sum to n:
            That is the unique way to do it.
            (Because we've already added enough coins to the pile to make
            the desired amount of change.)
        Otherwise, if the coins_so_far sum to more than n:
            There are no ways to do it.
            (Because there's already too much in our pile; we can't fix
            this by adding more.)
        Otherwise, if there are no coins_available:
            There are no ways to do it.
        Otherwise:
            (To make change for the rest of the pile, we either *do* add
            at least one more of the smallest possible coin, or we *don't*.)
            Every way to make change(for n cents, using the same
            coins_available, and which includes the coins_so_far
            as well as the first of the coins_available):
                Is one of the ways to do it.
                (Try adding a coin of the smallest denomination to the pile,
                and then figure out all the ways to make up the rest of the
                change. This finds the ways that do add the small coin.)
            Every way to make change(for n cents, using all the
            coins_available except the first, and including the
            coins_so_far):
                Is also a way to do it.
                (Find the ways that don't add the smallest coin denomination,
                by excluding it from the denominations we'll consider, and
                using the same process.)