python代码实践-程序员的算法趣题-Q05

这篇博客探讨了在公交零钱兑换机背景下,如何求解1000日元纸币兑换硬币的所有可能组合。提供了三种不同的算法解法,包括循环解法、贪心算法和递归算法,并通过实例解释了每种方法的思路。此外,还强调了在解决此类问题时,限制因素如硬币数量和最大兑换枚数的影响。
摘要由CSDN通过智能技术生成

Q05 还在用现金支付吗

        当下,坐公交或者地铁时大部分人都是刷卡的。不过,时至今日还在用现金支付的人还是比想象的多。本题我们以安置在公交上的零钱兑换机为背景。 这个机器可以用纸币兑换到 10 日元、50 日元、100 日元和 500 日元硬币的组合,且每种硬币的数量都足够多(因为公交接受的最小额度为 10 日元,所以不提供 1 日元和 5 日元的硬币)。兑换时,允许机器兑换出本次支付时用不到的硬币。此外,因为在乘坐公交时,如果兑换出了大量的零钱会比较不便,所以只允许机器最多兑换出 15 枚硬币。 求兑换 1000 日元纸币时会出现多少种组合?注意,不计硬币兑出的先后顺序。

参考答案:

解法一:应对本题,扩展性差

        因为题目中明显说明,兑换1000日元,则最多兑换2枚500日元的,10枚100日元的,15枚50日元,15枚10日元(不能超过15枚)。这样的话可以对每种情况循环求解。

def Divide():
    count = 0
    for i in range(3):  # 最多两种500的(另一个是15) 0-2
        for j in range(11):
            for n in range(16): # 最多15张 0-15
                for m in range(16): # 最多15张 0-15
                    total = 500*i + 100*j + 50*n + 10*m
                    if (i+j+n+m) <= 15:
                        if total == 1000:  # 对于这样的状况,肯定不会在大于1000时停止
                            count += 1
                            break
    print(count)
Divide()

解法二:贪心算法

        四种,一个一个试试,先从最大的 比如:需要1600,最多兑换20张 最多2个500,之后最多2个100的计算总数4张满足,每次都判断是都等于1200 之后最多2个500,之后最多1个100,两张50的 之后最多2个500,之后最多1个100,1张50的,5张10 之后最多1个500,之后最多7个100,...... 500: 20(大于1600)、19(大于1600)、28...3(小于1600,转到下层循环)、2、1 500 100: 20(1500+20个100大于1600)、19...

解法三:递归算法

        注意这里的i应该更多的是在表明递归层数,0-10,1-50,2-100,3-500,其实从本质上来说,i代表层数的对应的硬币面值不重要,都行,看整体上怎么做了,coins=[10,50,100,500] # 从小到大排,如果此时0-500,明显不合理,这样没法达到返回要求条件了。if i==n这里更多的应该是在判断如果此时递归处在第n层(和硬币面值对应),满足结束循环的前提条件,之后判断是否真正的能够结束循环即可。

        例如:以target = 1000,次数=15 在i=3时,对应着500,此时进行第4次(i=4),发现i=n=4,但是target != 0,则需要返回上一层,此层的i仍然为3(各层之间的函数内部的变量并不会互相干扰),此时t加1,将target-500后再次进行判断,此时i=n=4,但是target != 0,res仍然不变,返回上层.......,直到2个500时,满足条件,此时res+1,这个时候本次的第四层循环完毕,再次退回到第三层(i=2,100),此时target-100,再次调用,进行第四层循环,重复刚刚的过程,发现最终不满足条件,再次退回到第三层(i=2,100),此时target-2*100,再次调用,进行第四层循环,重复刚刚的过程,发现最终不满足条件,........,再次退回到第三层(i=2,100),此时target-5*100,再次调用,进行第四层循环,重复刚刚的过程,发现最终满足条件,res+1。这回本次循环第三层第四层皆已经完成,进入第二层重复上述操作。

        关于这里的i为什么从零开始: 1 i从0开始可以和列表下标开始位置对应 2 i和t值对应,而且t要从0开始(对应本题的coins来时,你不可能先加上一个10,再循环加上一个50... ,在加上500,这样的话,找不到所以情况。)

coins=[10,50,100,500] # 从小到大排
n=len(coins)
res=0
def dfs(target,i,usable):
    global res #修改全局变量
# 目的是为了先实验任何一个单张是否能行,# 当实验次数超过总的面值种类数时,说名单# 张不行,直接在res+1
    if i==n:
        res+=1 if target==0 else 0
        return
    coin=coins[i]
    t=0   # 这里很巧妙,层层递归
# 这里不满足也代表着程序执行结束
    while target-t*coin>=0 and usable-t>=0:
        dfs(target-t*coin,i+1,usable-t)
        t+=1
dfs(1000,0,15)
print(res)

注:根据程序员的算法趣题进行编写,仅供学习使用。

参考链接:程序员的算法趣题Q04:切分木棒_笨牛慢耕的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

B or D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值