CS61A 2021 HW3 Q4: Count coins

499 阅读4分钟

本人是新手,本次发文是因为在写该题过程中感觉这题的解题思想对我思维的扩展非常有价值,以此记录,如果你们会使用第二种函数的方法,可以留言,非常感谢!!!

image.png

image.png 译文:给定一个正整数变化,如果一组硬币的价值总和是变化的,那么一组硬币就会为变化而变化。这里我们将使用标准的美国硬币价值:1,5,10,25。例如,下面的集合更改为15:

15枚1分硬币

10枚1分,15分硬币

5个1分硬币,2个5分硬币

5个1分硬币,1个10分硬币

3个5分硬币

15美分,1枚10美分硬币

因此,有6种方法来改变15。编写一个递归函数count_coins,它接受一个正整数变化,并返回使用硬币进行变化的方法的数量。

你可以使用下列函数中的任意一个:

Ascending_coin将从输入中返回下一个更大的硬币面额,即Ascending_coin(5)是10。

Descending_coin将从输入中返回下一个较小的硬币面额,即Descending_coin(5)为1。

有两种主要方法可以解决这个问题。一种方法使用ascending_coin,另一种方法使用descent _coin。

重点:使用递归;如果使用循环,测试将失败。

提示:请参考count_partitions的实现,以了解如何计算以较小部分相加到最终值的方法。如果需要在递归调用中跟踪多个值,可以考虑编写一个作为帮助的函数。(我用的是****Descending_coin

image.png

image.png 题目中提示让我们参考count_partitions的实现方法,那么我们来看一下这个函数是怎么实现的

image.png 函数实现的是统计将n划分为较小的数相加的不同实现方法的数量,且规定k是用于划分的最大数,例如当k=3时,能用来划分的数只有1,2,3

实现这个函数count_partitions(5,3)我们首先要想怎么进行划分,我们在观察图中5的划分方法的时候,会发现方法一和方法二有3,剩下的没有,那就可以把所有的方法分成两部分,一个是至少有一个3的,剩下的是一个3也没有的,然后把这两部分统计到的数字加起来,就可以得到总共的方法。

image.png 我们再来看第一部分,也就是至少有一个3的这些方法,因为方法一和方法二都至少有一个3,所以我们把这个3抵消掉,然后看剩余部分,因为5-3=2,那剩余部分就是对2进行划分,然后求划分方法数,也就是实现函数count_partitions(2,3)

image.png 然后第二部分可以看成是函数count_partitions(5,2)的返回值,因此我们可以得出,count_partitions(5,3)=count_partitions(2,3)+count_partitions(5,2),然后count_partitions(2,3)和count_partitions(5,2)我们又可以用同样的方法进行划分,也就是count_partitions(n,m)=count_partitions(n-m,m)+count_partitions(n,m-1)这就是树递归的思想。

那我们应该怎么处理返回值呢,我们发现要解决这个问题不能直接看出或者根据经验看出,这个时候我们就要把一个确切的值带进去调试,然后通过调试来判断函数应该怎么返回。

我们以count_partitions(5,3)为例进行调试,我们发现,当n<0时,已经不存在方法了,所以要返回0,当n=0时,只有一种方法存在,例如f(2,2)->f(0,2)这一过程,只有唯一方法2=2,所以返回1。当m=时,也是只有一种方法,例如f(2,1)为2=1+1,也就是返回1,那么这三个就可以作为函数调用的结束条件。

image.png 我们在理解了上面这个思路之后,再来做这道硬币题就很简单了,思路是换汤不换药的,只要把count_partitions(n,m)中的m作小小变化就行了,以题目中的15为例,划分数规定为1,5,10,25,又因为题目提供的函数Descending_coin(25)=10。 于是可以很容易写出解析

def descending_coin(coin):
    if coin == 25:
        return 10
    elif coin == 10:
        return 5
    elif coin == 5:
        return 1

def count_coins(change):
    def f(n,m):
        if n<0:
            return 0
        elif n==0:
            return 1
        elif m==1:
            return 1
        else:
            return f(n,descending_coin(m))+f(n-m,m)
    return f(change,25)

print(f"count_coins(15)'s value is {count_coins(15)}")

image.png