百炼1664,放苹果:http://poj.grids.cn/practice/1664
分枚举和计数两类解法。计数更为快捷。解法一和解法二分别是两类不同的计数方法。解法三是枚举法。
解法一:
设f(m,n) 为m个苹果,n个盘子的放法数目则有:
①当n>m:必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) f(m,n) = f(m,m)。
②当n<=m:不同的放法可以分成两类:
a、有至少一个盘子空着,即相当于f(m,n) = f(m,n-1);
b、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m,n) = f(m-n,n).
而总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n) 。
相关分析及代码,可参考:
简洁版:http://www.cnblogs.com/dongsheng/archive/2012/08/15/2640468.html
值记录版:http://blog.csdn.net/jackyzhengx1990/article/details/6049218
另,简洁、且记录函数调用返回值的Python代码如下。
#版本:python v3.3.0 import sys from functools import lru_cache #根据参数建表,保存已调用过的函数的返回值 @lru_cache(maxsize=None) def counter(m, n): if m == 0 or n == 1: return 1 if n > m: return counter(m, m) else: return counter(m, n-1)+counter(m-n, n) #重定向输入输出 sys.stdin = open("1378.in", "r") sys.stdout = open("1378.out", "w") line = input() n = int(line) for i in range(n): #读入m、n的值。 line = input() m, n = [int(num) for num in line.split()] #计算并输出结果 print(counter(m ,n))注:其中通过装饰器函数lru_cache自动记录调用过的counter函数的返回值。这样,下次以相同的参数调用counter函数时,将直接返回之前计算所得值。
解法二:
将这个问题转化为正整数的有序分拆。我们用B(m, n)来表示m的n分拆的个数。所谓m的n分拆,是指将正整数m拆分为n个正整数之和。例如:B(3, 2)=1,仅“3 = 1 + 2”一种拆法。B(4, 2)=2,有“4=1+3、4=2+2”两种拆法。
那么,将m个相同的苹果放入n个相同的盘子中,也就相当于将m拆分为n个非负整数之和。记A(m, n)为将m个苹果放入n个盘子中的放法。应有A(m, n)=B(m, 1)+B(m, 2)+B(m, 3)+.....B(m, n)。
又B(m+k, k)=B(m, 1)+B(m, 2)+B(m, 3)+B(m, 4)+....B(m, k),且有B(m, 1)=1, B(m, m)=1。于是求解A(m, n)转化为递归求解B(m+n, n)。
相关资料可参考:
其中B(m, n)递归式来源(定理2.6.3):http://wenku.baidu.com/view/3a9c541c0b4e767f5acfced9.html
整数无序分拆:http://en.wikipedia.org/wiki/Partition_(number_theory)
整数有序分拆:http://en.wikipedia.org/wiki/Composition_(number_theory)
解法三:
枚举所有可能的分拆。
将m个相同的苹果放入n个相同的盘子可能的放法等价于求出下列方程解的个数:
m = a1+a2+a3+....+an,其中0≤a1≤a2≤a3≤....≤an≤m
可通过枚举上述式子解的个数求解。代码如下:
#版本:python v3.3.0 import sys def place(apple, bowl, last): global counter #声明全局变量 if bowl == 1: if apple >= last: counter += 1 return if apple < last: return for i in range(last, apple+1): place(apple-i, bowl-1, i) #重定向输入输出 sys.stdin = open("1378.in", "r") sys.stdout = open("1378.out", "w") line = input() n = int(line) for i in range(n): #读入m、n的值。 line = input() m, n = [int(num) for num in line.split()] #初始化counter,计算并输出结果 counter = 0 place(m ,n , 0) print(counter)