背景
递归的关键在于:本次状态和上次状态之间的差异
理解
将m个苹果放到n个盘子中,有多少种放法?即求f(m, n)。
这个问题关键在于不同数量的苹果和盘子之间的方法关系,即只需要考虑多出来的苹果怎么放。因为:
- 如果m<n,由于多出来的盘子并不会影响放法种数,所以f(m, n) = f(m, m)。
- 如果m≥n,则存在两种情况:
- 有空盘,就相当于本身少了空盘的放法,所以f(m, n) = f(m, n-1)。(该公式递推多次即是多个空盘的情况)
- 无空盘,就相当于每个盘都有一个苹果,因为关键在于多出来的盘怎么放,那么每个盘拿掉一个苹果也不影响放法种数,所以f(m, n) = f(m-n, n)。
总的放法种数等于两者的和,即f(m, n) = f(m, n-1) + f(m-n, n),也就是盘在减少的情况+苹果在减少的情况。
那么,最终盘会减少到n == 1,苹果会减少到m == 0,此时都只有1种放法。这里也就是递归的出口。
import sys def func(m, n): """ 苹果放到盘子上只有下面两种情况: 1. 有一个盘子是空的,则(m,n)的放置问题,变成了(m,n-1) 2. 没有盘子是空的,则考虑剩下的苹果怎么放,变成了(m-n,n) 备注:有多个盘子是空的,其实就是多次的一个盘子是空的递推问题 :param m: 苹果数量 :param n: 盘子数量 :return: 方法数量 """ if m == 0 or n == 1: return 1 elif n > m: # 由于每个盘拿掉一个苹果,所以可能存在空盘情况,也需要考虑进去 return func(m, m) else: return func(m, n-1) + func(m-n, n) # 两种情况的方法数量之和 for s in sys.stdin: m, n = map(int, s.split()) # 格式化输入的m和n if m < n: # 存在空盘情况 n = m print(func(m, n))