硬币问题(瓜子网二手车试题)
有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱(n <= 100000),有多少中组合可以组成n分钱?
我只知道使用多重for循环进行暴力求解,效率很低,数字高了后算不出来。
答案中提供了一个很巧妙的方法。但我看不懂。
几经钻研后,搞懂了。主要参考了这篇文章。
# python3
def change(coins, n):
len1 = len(coins)
if len1 == 0 and n < 1 or n > 100000:
return None
ways = [0] * (n + 1) # 初始化
ways[0] = 1
for i in range(len1):
for j in range(coins[i], n + 1):
# 保证n小于等于100000,为了防止溢出,请将答案Mod 1000000007
ways[j] = (ways[j] + ways[j - coins[i]]) % 1000000007
print(ways[n])
if __name__ == '__main__':
coins, n = [1, 2, 5, 10], int(input())
change(coins, n)
我们应该都还记得迈台阶问题。一次性可以迈1-2阶,递推关系如下。
F(N)=F(N-1)+F(N-2)
那么对于硬币问题,也可以视为一次增加1,2,5,10级台阶,最终凑到n阶就可了。
那么是否有:
F(N)=F(N-1)+F(N-2)+F(N-5)+F(10)呢?
当然不是。例如在N-5级台阶的时候,此时到N的方法显然不止一种。甚至可以说是有多种的。因而,也应该要把F(6)等给算上。
因为可以选择的情况太多了,导致上面这种简单的递推关系式就不成立了。
因而我们尝试让任何时候都只有两个选择。从简单的两种硬币1,2开始。
此时显然有:
F(N)=F(N-1)+F(N-2)
F(1)=1
如果只使用硬币1
F(N)=F(N)+F1(N-1)
其中F1是使用当前所有类型的硬币的数目。
如果同时使用2
F(N)=F(N)+F1(N-1)
+F2(N-2)
其中F1来自硬币1,F2来自硬币2
此时如果把硬币5加上。
F(N)=F1(N)+F2(N-5)
每一个点N可以如此构成,只含1的方法个数,只含1,2的方法个数,125方法个数,12510方法个数。
对任何一个F(N)只含一的方法个数一定是1。
含有2的方法个数就是从第一个可以被2更新的点3,每个点F(N)+=F(N-1)
最终还是发现问题描述不清楚。。。该死的。算了。