11-放苹果

再看一下用递归将问题分解为规模更小的子问题进行求解的例子。

1、问题描述

把 M 个同样的苹果放在 N 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?5,1,1和1,5,1 是同一种分法。
输入
第一行是测试数据的数目 t(0 <= t <= 20)。以下每行均包含二个整数 M 和 N,以空格分开。1<=M,N<=10。
输出
对输入的每组数据 M 和 N,用一行输出相应的 K。

样例输入
1
7 3
样例输出
8

2、问题分析

我们假设将 i 个苹果放在 k 个盘子里放法总数是 f(i,k)。
现在对 i 和 k 的值进行讨论,

  1. 当 k>i 时,f(i,k)=f(i,i)
    公式解析:这个时候盘子多,苹果少,i 个苹果最多只能占用 i 个盘子,剩余的空盘子可以拿走了,因为一定是空的,相当于 i 个苹果,i 个盘子有多少种放法。
  2. 当 k<=i 时,总放法 = 有盘子为空的放法 + 没盘子为空的放法
    f(i,k)=f(i,k-1)+f(i-k,k)
    公式解析:有盘子为空,则至少一个盘子为空,将一个空盘子拿走,就变成了 i 个苹果放 k-1 个盘子;没有盘子为空,就是每个盘子至少有一个苹果,先将每个盘子放一个苹果,再将剩下的 i-k 个苹果放 k 个盘子中。

再看一下边界条件,f(i,k-1) 使得 k 减小,所以要设置一个 k 的下限阻止无穷递归下去,f(i-k,k) 使得 i 减小,但是i的值不会小于0,因为 k<=i;所以也要设置 i 的下界,阻止无穷递归。

  1. 当k=0时,没有盘子,有i个苹果,放法是0;
  2. 当i=0时,没有苹果了,只有一种放法,空着。

程序如下:

#include<iostream>
using namespace std;
//把m个同样的苹果放在n个同样的盘子里
int f(int m, int n)
{
	if (m == 0)			//没有苹果了
		return 1;
	if (n == 0)			//没有盘子了
		return 0;
	if (m < n)
		return f(m,m);
	return f(m, n-1) + f(m-n, n);//总放法= 有盘子为空的放法+没盘子为空的放法

}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int m, n;
		cin >> m >> n;
		cout << f(m,n)<<endl;
	}
	return 0;
}

3、总结

1、学习将问题分解为规模更小的子问题
2、学会寻找边界条件

猜你喜欢

转载自blog.csdn.net/happyjacob/article/details/87729861