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

【题解】放苹果(1)

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

【题目描述】

把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;
}


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

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

标签: 递归
分享给朋友:

相关文章

【题解】开关灯(2)

1.开关灯(light.cpp)【题目描述】某实验室共有n盏灯,灯的编号为1~n,每盏灯的初始状态是关闭的。现在有m位学生,每位学生可以前去抽取一张带数字的卡片,其数字为Ai,然后依次将自己手中的数字...

【题解】2020-T1 优秀的拆分

【题目描述】一般来说,一个正整数可以拆分成若干个正整数的和。例如,1=1,10=1+2+3+4等。对于正整数n的一种特定拆分,当且仅当在这种拆分下,n被分解为若干个不同的2的正整数次幂。注意,一个数x...

奶牛的耳语

【题目描述】在你的养牛场,所有的奶牛都养在一排呈直线的牛栏中。一共有 n头奶牛,其中第 ii头牛在直线上所处的位置可以用一个整数坐标 pi(0<pi<10^8...

2021年市北区程序设计竞赛题(⼩学组)

最⼤值的相乘(maxx.cpp)【问题描述】第⼀⾏有x个正整数a1,a2,..,ax,第⼆⾏有y个正整数b1,b2,...,by,第三⾏有z个正整数c1,c2,...,cz,假设第⼀⾏的x个正整数中的...

【题解】解密

【题解】解密

【题目描述】给定一个正整数k,有k次询问,每次给定三个正整数ni,ei,di,求两个正整数pi,qi。使ni=pi *  qi,  ei * di =(pi -1) *(qi-1)...

【题解】求最长不下降序列

【题目描述】设有由n(1≤n≤200)个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)且b(i)≠b(j)(i≠j),若存在i1<i2<i3<…<ie 且有b...