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);
		}
	}
}
  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值