900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > M个苹果放到N个相同盘子和N个不同盘子的解法

M个苹果放到N个相同盘子和N个不同盘子的解法

时间:2018-08-04 07:30:24

相关推荐

M个苹果放到N个相同盘子和N个不同盘子的解法

题目很简单:就是把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);}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。