POJ1664
题目:
Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Sample Input
1
7 3
Sample Output
8
对输入的每组数据M和N,用一行输出相应的K。
(摘自http://poj.org/problem?id=1664)
解决函数:
int num(int apple,int baket)
{
if(baket<=0||apple<0)
return 0;
if(apple1||baket1)
return 1;
return num(apple,baket-1)+num(apple-baket,baket);
}
本质: 讨论N个自然数(>=0)合为M时,N的组合的可能。如M为3,N为3,N的组合可能就有{0,0,3},{0,1,2},{1,1,1}三种(忽略重复情况)
分析:(以递归形式为手段展开讨论)
首先阅读题干可知我们讨论的就是N个数字的组合问题
而已知N或M为1的情况下,组合只有一种。此外{1,5,1}与{5,1,1}为一种情况。
为了避免重复,我们可以对N个数字由小到大展开讨论,后一个数比前一个数大或二者相等。如{x,y,z},x<=y<=z。设置函数 int num(M,N);(m表示剩余的苹果,N表示剩下的篮子)
则有(1)x=0的时候,y+z=M. N=N-1;
(2)x不为0的时候,y和z一定不比x小,如x为1,{x,y,z}={1,1+a,1+b}
在对分类的讨论上{1,1+a,1+b}=={0,a,b} 二者分类的情况相同(a+b=M-N,N数目不变)
即N=N,M=M-N;
此外1是最基本的正整数,所以我们可以由1为单位从0开始逐渐递增最小数字的大小
综合(1)(2),做出如下num函数雏形
int num(M,N){ return num(M,N-1)+num(M-N,N);}
//num(M,N-1)是对最小数为0情况的讨论 num(M-N,N)是对最小数不为0的讨论,
结合本题例子(7果3盘子)
重复两次num(M,N-1) 就会有 num{7,1}
重复2次num(M-N,N)就会有num(1,3)实际代表{2,2,3}情况
出现上述两种情况的时候我们就可以归类为函数返回值为1,
也就是if(N==1||M==1) return 1;
但是同时这也会产生一些错误数据
如num(M-N,N)重复三次,就会有num(-2,3)
而重复十次num(M,N-1)也会有num(7,-7)
所以用if(N<=0||M<0)return 0; 来防止函数产生错误数据
然后写到这里我想大家也许会有疑问,为什么把N小于等于0与return0挂钩,而M却只有小于0.
其实大家不妨想想M=0的情况,这里M减小只有一种途径,即M-N,M等于0时,可以说是M平分给了N个盘子(这里的N 未必是一开始的N),而后M=0,N>0, 则(num(0,N-1)+num(0-N,N))==num(0,N-1)+0=num(0,1+a)=num(0,1)=1,并不会产生错误函数。
综上 构建出递归函数
int num(int apple,int baket)
{
if(baket<=0||apple<0)
return 0;
if(apple1||baket1)
return 1;
return num(apple,baket-1)+num(apple-baket,baket);
}