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

【题解】放苹果(1)

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

【题目描述】

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


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

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

标签: 递归
分享给朋友:

相关文章

【题解】月度开销

【题目描述】农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来N(1 ≤N≤ 100,000) 天里每天需要的开销。约翰打算为连续的M(1 ≤M≤N)...

【题解】移动路线

【题目描述】X桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。小明是个调皮的孩子,一...

2021年青岛市程序设计竞赛试题(初中组)决赛

2021年青岛市程序设计竞赛试题(初中组)决赛

A.趣味三角(triangle.cpp) 【题目描述】 今天,新高一的OIer们第一次进入了机房。z老师想让他们喜欢上OI,于是给了他们每个人一个三角形。 这时候,小q秃发奇想,...

【题解】最长上升子序列

【题目描述】一个数的序列bi,当b1<b2<...<bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1,a2,...,aN),我们可以得到一些上升的子序列(ai1,ai2,...

【题解】愤怒的牛

【题目描述】农夫 John 建造了一座很长的畜栏,它包括N(2<=N<100000)个隔间,这些小隔间依次编号为x1,x2,...xn(0<=xi<=1000000000)。但...

【题解】最大配对

题目描述      给出2个序列A={a[1],a[2],…,a[n]},B={b[1],b[2],…,b[n]},从A、B中各选出n个元素进行一一配对(可以不按照原来在...