[关闭]
@xudongh 2017-03-10T20:26:03.000000Z 字数 1437 阅读 3616

函数的递归--m个苹果放进n个盘子

计算机


题目描述

问题:M个苹果放入N个盘子,有多少种分法?


解题思路

假设存在一个函数能算出当我们m个苹果放到n个盘子里的时候,有多少中解决方案。分析一下这样一个函数是如何进行运算的。

对于这道题目,分情况讨论:

1、 当n/盘子数 > m/苹果数

由于盘子数大于苹果数,这意味着就算每个盘子只放一个苹果,总会有(m-n)个盘子是空着的,这(m-n)个盘子对于苹果的放置方法不会产生任何影响。所以可以把多余的盘子拿掉。因此有:

  1. if(n>m){
  2. f(m,n) = f(m,m);
  3. }

2、当n/盘子数 < m/苹果数

根据题意,允许有的盘子空着不放。根据这个条件,把所有的放置方法分成两大类:

① 有盘子空着
② 没盘子空着

所有可能存在的放置方法的数目就等于分别在这两种情况下出现的放置方法数目的加和。
对以上两种情况再进行分析:

① 有盘子空着

在这个条件下,总是至少有一个盘子是空着的,而这一个空着的盘子对苹果的放置方法不会产生任何影响,这与条件1一样,可以把这个多余的盘子拿掉。因此有:

  1. if(n <= m){
  2. f(m,n) = f(m,n-1); //有盘子空着的情况
  3. }

② 没盘子空着

在这种条件下,每个盘子都至少放有一个苹果。由于每个盘子里至少放着的那只苹果对于放置方法不会产生任何影响,因此我们又可以把每个盘子里那只多余的苹果拿掉。因此有:

  1. if(n <= m){
  2. f(m,n) = f(m-n,n); //没盘子空着的情况
  3. }

这时,当每个盘子欧度拿掉一只苹果只有,我们又回到了条件1讨论的那种情况,即盘子数大于苹果数。因此又可以拿掉多余的盘子。

在拿掉多余的盘子的基础上,我们又回到了条件2所讨论的那种情况,即盘子数等于苹果数。在这种情况下,放置方法又可以分为①有盘子空着②没盘子空着两类。所以按照这种思路,可以一直分析下去。

到最后,只剩下一个盘子或者一个苹果,这时分析就结束了。

按照这种规律,我们已经把所有可能出现的情况全部都进行了分类,而我们需要得到的结果,就是把所有这些情况下的结果进行加和。

未标题-1.png-38.7kB

用C语言表述为:

  1. #include<stido.h>
  2. int count(int m,int n);
  3. int main(){
  4. int apples;
  5. int plates;
  6. scanf("%d %d",&apples,plates);
  7. printf("%d",count(apples,plates));
  8. return 0;
  9. }
  10. int count(int m, int n){ // m为苹果数,n为盘子数
  11. if(m <= 1 || n <= 0)
  12. return 0;
  13. if(m<n)
  14. return count(m,m);
  15. else
  16. return count(m,n-1)+count(m-n,n);
  17. }

可以发现,虽然在分析过程中,解题思路比较复杂,但在程序语言中少量简短的语句便可以描述出来。


总结

为什么可以用这么简短的程序分析清楚这么多种情况呢?在这种场景中,递归帮我们进行自动分析。
运用递归设计程序的时候,其方法在于:

  1. 先假设有一个函数fun()能够给出我们所需要答案,把关注点放在要求解的目标上(连续发生的动作是什么);
  2. 利用这个函数fun()的前提下, 分析如何解决问题,利用fun()来表示fun(),找出第n次执行与第n-1次执行之间的关系(不同次动作之间的关系);
  3. 弄清楚在最简单的情况下,其答案是什么,确定第1次的返回结果(边界条件是什么)。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注