当前位置:首页 > 题解目录 > 正文内容

【题解】放苹果(1)

亿万年的星光4年前 (2021-05-01)题解目录4168

【题目描述】

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

【输入】

第一行是测试数据的数目t(0≤t≤20)。以下每行均包含二个整数M和N,以空格分开。1≤M,N≤10。

【输出】

对输入的每组数据M和N,用一行输出相应的K。

【输入样例】

1
7 3

【输出样例】

8

【题目分析】

  • 比较经典的递归题目(排列组合)

  • 加上限制条件,一共可以催生出8种不同的题目(例如,盘子允许空或者不空就是两种情况)

  • 先分析样例,然后总结规律,最后用公式代替(递归的主要思路)

  • 也可以用递推规律去分析

  • 所有苹果都必须放完



【从样例分析递推规律】

按照题目样例,7(M)个苹果放到3(N)个盘子中。可能存在下面几种情况。

第一类:

7   0   0
6   1   0
5   2   0
4   3   0

第二类:

5   1   1
4   2   1
3   3   1
3   2   1

可以看出一共有8种,可以分成两类。


下面我们开始列举其他数据分类讨论寻找规律。

第一类:M<N时:

  • 假设1(M)个苹果放到2(N)个盘子中。只有1(M)种放法,而且至少空1(N-M)个盘子

  • 假设1  (M)  个苹果放到3 (N)个盘子中。只有1(M)种放法,而且至少空2(N-M)个盘子

  • 假设2(M)个苹果放到3(N)个盘子中。 只有2(M)种放法,而且至少空1(N-M)个盘子

  • 假设2(M)个苹果放到4(N)个盘子中。 只有2(M)种放法,而且至少空2(N-M)个盘子......

可以看出,当N>M时,放法只有M种。N的大小不影响不同的放法种数。如果放到递归中,也就是f(m,n)=f(m,m)

第二类:M>=N时:

从样例数据可以看出,M>=N时,可以继续分成两类,包含空盘子(0)和不包含空盘子的情况。那么,我们继续分析

  • 假设2(M)个苹果放到1(N)个盘子中。只有1种放法,没有空盘子

  • 假设3(M)个苹果放到1(N)个盘子中。只有1中放法,没有空盘子

  • 假设3(M)个苹果放到2(N)个盘子中。有2种放法(按照有没有空盘子分)。(3,0)和(2,1)

  • 假设4(M)个苹果放到2(N)个盘子中。有3种放法(按照有没有空盘子分)。(4,0)、(3,1)、(2,2)

  • 假设4(M)个苹果放到3(N)个盘子中。如果有一个空盘子,就是4个苹果放到2(N-1)个盘子中,那么跟上面的f(4,2)是一种情况。如果每个盘子至少一个。那么就是先相当于“先把每个盘子中放一个,剩余M-N个苹果放到N个盘子中”(注,此时M-N一定小于N,也就是跟第一类情况吻合)。那么这种情况就是

    F(M,N)=F(M,N-1)+F(M-N,N)。

    继续举例验证公式:

  • 假设5(M)个苹果放到3(N)个盘子中。F(5,3)一共有下面5种。

5 0 0
4 1 0
3 2 0

3 1 1
2 2 1

F(M,N-1)=F(5,2)=3种

5 0

4 1
2 3

  F(M-N,N)=F(2,3)=2种(第一类已经证明了)

所以,递归的结论是:

M<N时:F(M,N)=F(M,M)

M>=N时:F(M,N)=F(M,N-1)+F(M-N,N)

递归出口条件:

  • 当n=1时,所有苹果都必须放在一个盘子里,所以返回1;

  • 当m==0(没有苹果可放)时,定义为1种放法;

所以递归部分核心代码是:

int fun(int m, int n) {//m个苹果放在n个盘子中共有几种方法
    if(m==0 || n==1)
        return 1;
    if(n>m)
        return fun(m,m);
    else
        return fun(m,n-1)+fun(m-n,n);
}


【递推规律】

除了递归外,我们还可以尝试用递推去做,最好的办法就是“表格法”(打表法)




N=0N=1N=2N=3N=4N=5N=6
M=0x111111
M=1x1
11111
M=2x1
22222
M=3x1
2
33
33
M=4x13
4
555
M=5x13
5677
M=6x147910
11

注:并建议编程题用这种做法,即时画出表格,规律也不好总结


【DFS】

#include<iostream>
using namespace std;
int t,n,k;
int f[11][11];
int sum;
 
void dfs(int step,int num,int tar)
{
	if(tar==1)
	{
		sum++; 
		return ;
	}
	for(int i=step;i<=num/tar;i++)
		dfs(i,num-i,tar-1);
}
 
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		sum=0;
		dfs(0,n,k);//因为可以有空盘,所以从0开始 
		cout<<sum<<endl;
	}
	return 0;
}


扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

标签: 递归
分享给朋友:

相关文章

【题解】排队买票

【题目描述】有M个小孩到公园玩,门票是1元。其中N个小孩带的钱为1元,K个小孩带的钱为2元。售票员没有零钱,问这些小孩共有多少种排队方法,使得售票员总能找得开零钱。注意:两个拿一元零钱的小孩,他们的位...

【题解】感应门

【题目描述】感应门会在有人经过的时候自动打开,冷却d 秒后自动关闭。如果有人在感应门打开的状态下通过,那么冷却时间会重置,重新冷却d秒后再关闭。在一段时间内,有 n个人陆续通过了感应门,他们...

【题解】奇偶校验

【题目描述】奇偶校验(Parity Check)是一种校验代码传输正确性的方法。根据被传输的一组二进制代码的数位中“1”的个数 是奇数或偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。现在给...

字符串反连接

【题目描述】写一函数,使输入的一个字符串按反序存放,在主函数中输入并输出反序后的字符串(不包含空格)。【输入描述】一行字符【输出描述】逆序后的字符串【样例输入】123456abcdef【样例输出】fe...

【题解】合唱队形

【题目描写】N位同学站成一排,音乐老师要请其中的(N−K)位同学出列,使得剩下的KK位同学排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K,他们的身高分别为T1,T...

2020CSPJ-直播获奖

【题目描述】NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为w%,即当前排名前 w% 的选手的最低成绩就是即时的分数线...