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)
注:根据程序员的算法趣题进行编写,仅供学习使用。