题目很简单:就是把m个苹果放到n个盘子中,盘子可以为空,问你有多少种放法。
首先应该明白,盘子相同时三个盘子放1 1 5 和 5 1 1 是相同的,盘子不一样时是不同的放法。
(1)放入相同盘子 苹果为m, 盘子为n
放苹果时分为两种可能:一种是苹果数大于等于盘子数,第二种是苹果数小于盘子数。f(m,n)是求方法数的函数。
当m < n时,一定会有(n-m)个盘子空着,或者说至少会有(n-m)个盘子空着,这几个盘子对于接下来的苹果摆放一点影响都没有,直接去掉他们。所以有了 return f(m, m); 剩下的盘子数等于苹果数等于m.
当m >= n时,又可以分为两类:一类时有盘子为空(也就是包含0),第二类时盘子都不为空(不包含0)。
第一类(含0):肯定至少有一个盘子是空着的,所以就是 f(m, n-1)
第二类(不含0):先把每个盘子都放一个苹果,这放上去的n个苹果对剩下的苹果摆放没有影响,直接去掉即可,所以有f(m-n, n);
递归出口:
n == 1 所有苹果都放到一个盘子里 (这里f(m,n)可以看作是把m个苹果放到n个盘子上)
m == 0 没有苹果的时候
代码:
int f(int m, int n)
{
if (m == 0 || n == 1)
{
return 1;
}
else if (m < n)
{
return f(m, m);
}
else if (m >= n)
{
return f(m, n-1)+f(m-n, n);
}
}
下面是志志的深搜方法,如果上面的看不懂可以试着理解理解这个。时间上比上面多一些。
void Dfs(int x, int step, int y)
{
if (step>m || x>step)
{
return;
}
else if (x==m && step==n)
{
sum++;
}
else
{ //y是上一个递归循环中的i,保证了接下来放的苹果个数只会比前一个大或者等于前一个
//因为盘子相同时1 1 5 和 5 1 1 是一样的,这样就防止了5 1 1 出现的可能
for (int i=y; i<=m; i++)
{
dfs(i+x, step+1, i);
}
}
}
(2)M个苹果放到N个不同的盘子中
思路和盘子不同是差不太多,只是多了一个组合数(在这里用Comd(n, m), 表示从n个中选出m个)。
开始分为两种可能:
当 m < n 时,m个苹果可以在n个盘子里选m个,也就是Comd(n, m)个,身下的(n-m)个盘子已经被考虑过了,而且不会影响接下来的摆放,直接去掉就行,所以方法数有 Comd(n, m) * f(m, m)
当 m >= n时,分为有盘子为空(有0)和盘子均不为空(无0):
有0时:从n个盘子中选出一个不放苹果,有Comd(n, 1)种选法,所以就是Comd(n, 1) * f(m, n-1)
无0时,从m个苹果中先拿出n个放满盘子,这n个苹果对后序摆放没有一点影响,直接去掉就行,然后就变成了(m-n)个苹果摆放在n个盘子问题 也就是 f(m-n, n)
递归出口(同盘子相同时一样)
int f(int m, int n)
{
if (m==0 || n==1)
{
return 1;
}
else if (m < n)
{
return Comd(n, m) * f(m, m);
}
else if (m >= n)
{
return Comd(n, 1)*f(m, n-1) + f(m-n, n);
}
}
组合数函数就需要你们自己搞了,不过我是咋打咋wa,最后还是用DFS才ac。
void dfs(int x, int step)
{//x是已经放的苹果数,step是已经用掉的盘子数
//因为盘子是不相同的所以1 1 5 和 5 1 1是不同的了
if (x==m && step==n)
{
sum++;
}
else if (x>n || step>m)
{
return;
}
else
{
for (int i=x; i<=n; i++)
{
dfs(i, step+1);
}
}
}