`
Touch_2011
  • 浏览: 290465 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论
阅读更多
1.递归的思想:

设计一个递归函数,明确这个递归函数的定义,在这个函数里面反复调用自己从而求出问题的解。递归很多时候用于求有多少种解法的题目:这时要分清有多少种情况,然后把每一种情况产生的解的个数相加。

2.例题分析

1)放苹果:M个同样的苹果放N个同样的盘子,允许有盘子空着, 问有多少种放法。注意:5 1 11 5 1是同一种放法

     分析:分两种情况:a.至少有一个盘子为空,此时放法种数与减去这个空盘子的放法种数相同。b.所有盘子都不为空,此时可以从每个盘子里拿掉一个苹果而不影响放法种数。

显然m<n时,只能满足第一种情况.

     代码:

#include<stdio.h>

 

//m个苹果放n个盘子里的放法种数

int setApple(int m,int n)

{

         if(m<=1||n==1)

                   return 1;

         if(n==0)

                   return 0;

         if(n>m)//至少有一个盘子为空

                   return setApple(m,n-1);

         else//至少一个盘子为空 + 所有盘子都不为空

             return setApple(m,n-1)+setApple(m-n,n);

}

 

void main()

{

         printf("%d\n",setApple(7,3));

}

2)红与黑:有一间房子铺有红色和黑色的砖块,人站在一个黑色砖块上面,且每次只能移动到黑色砖块,不能走走过的砖块。求他所能到达的黑色砖块的数目。如:

char house[9][6]={

{"......"},

{".@..##"},

{"..#.#."},

{".#.##."},

{"#...#."},

{"....#."},

{"....#."},

{"....#."},

{".....#"}

};

‘.’表示黑色砖块,’@’表示黑色砖块且人所在的当前位置,’#’表示红色砖块

分析:分四种情况,上、下、左、右。这四种情况下所能到达的数目和当前位置加起来就是总共能到达的数目.

代码:

#include<stdio.h>

 

char house[9][6]={

{"......"},

{".@..##"},

{"..#.#."},

{".#.##."},

{"#...#."},

{"....#."},

{"....#."},

{"....#."},

{".....#"}

};

int m=9;

int n=6;

 

//求初始位置在(ij)时能到达的黑砖的个数

int move(int i,int j)

{

         if(house[i][j]=='@')

       house[i][j]='.';

         if(i<0 || j<0 || i>=m || j>=n || house[i][j]!='.')

                   return 0;

         else//到达过的做标记

                   house[i][j]='0';

         //每个点有四种走法

         return 1+move(i-1,j)+move(i+1,j)+move(i,j-1)+move(i,j+1);            

}

 

void main()

{

         printf("%d\n",move(1,1));

}


3)计算3A2B可以组成多少种排列的问题(如:AAABB, AABBA)是《组合数学》的研究领域。但有些情况下,也可以利用计算机计算速度快的特点通过巧妙的推理来解决问题。下列的程序计算了mAnB可以组合成多少个不同排列的问题。请完善它。

int f(int m, int n)

{

    if(m==0 || n==0) return 1;

    return ____ f(m-1, n) + f(m, n-1)___________________;

}

    分析:首先明确这个函数的功能是:求mAnB可以组成多少种排列。此时分两种情况:a.排列的第一个元素是Ab.排列的第一个元素是B。把这两种情况的排列种数加起来即可.

   4)某布袋中有红球m个,白球n个,现在要从中取出x个求,红球数目多于白球的数目的概率是多少。下面的代码解决这个问题,其中y表示红球至少要出现的次数。

m , n, x, y为仅存线索

double f( int m, int n, int x,int y)

{

if(y>x) return 0;

if(y==0) return 1;

if(y>m) return 0;

if(x-n>y) return 1;

double p1=________________; f(m-1,n,x-1,y-1)

double p2=________________; f(m,n-1,x-1,y)

return (double)m/(m+n)*p1+(double)n/(m+n)*p2;

}

    分析:明确函数的定义:求m个红球、n个白球的布袋中取出x个球,红球数目大于白球的概率。注意到m/(m+n)表示取出的球是红球的概率,n/(m+n)表示取出的球是白球的概率。现在从布袋中取一个球出来,有两种情况:a.取出的是红球 b.取出的是白球.然后根据不同的情况判断mnxy的变化。

5假设有m+n个人,其中,m个人手持面额为5角的硬币,n个人手持面额为1元的硬币,他们都要乘车买票,现假设售票员手中无零钞,票价为5角,下面这个函数就可以算出这m+n个人所有可能的买票情况(顺利完成购票过程的购票次序的种类数,请完善此函数

int f(int m, int n) 

        if(m < n) return 0; 
        if(n==0) return 1; 
        return ____ f(m-1 , n) + f( m-1 , n-1) ___; 
}

分析:这题跟上题有点相似,上题是模拟从布袋中取一个球出来,这个球可能是红球,也可能是白球。这里是模拟一个人上车,这个人可能是持5角的硬币,也可能是持1块的硬币。第一种情况下这个人直接上车,第二种情况下手持1块钱硬币的人要等有一个手持5角的人上车。

 

3.总结

  递归是很多算法的基础,递归的难点是构造递归函数和分清楚情况。在分情况时很多都是模拟现实中的情况,如上面的第145题。

4.递归函数设计

1)整数划分

如,对于正整数n=6,可以分划为:

6

5+1

4+2, 4+1+1

3+3, 3+2+1, 3+1+1+1

2+2+2, 2+2+1+1, 2+1+1+1+1

1+1+1+1+1+1+1

总共有十一种划分,求一个数总共有多少种这样的划分。

 

代码:

/*

 * 整数划分

 * 划分出去一个整数, n==m 时,有两种情况:

 *

 * 划分出去的整数等于n+划分出去的整数小于n

 

 * n>m时:

 * 划分出去的数小于m+划分出去的数等于m

 *

 */

 

#include<stdio.h>

 

//正整数n最大加数n1不大于m的划分个数

int divide(int n,int m)

{

     if(n==1 || m==1)

              return 1;

     if(n<m)

              return divide(n,n);

     else if(n==m)

              //最大加数等于n+最大加数<n

              //比如n=6:最大加数是6的划分的划分个数+6不大于5的划分个数

              return 1+divide(n,m-1);

     else

              //最大加数小于m的个数+最大加数为m时的个数

              //n=6m=26不大于1的划分个数+4不大于2的划分个数

              //(处理m=2的那一行,其中这行减2之后就是4不大于2的划分个数)

              return divide(n,m-1)+divide(n-m,m);

}

2)木棍问题

 一组等长的的木棍,随机的截断,使每一段不超过50个长度单位。然后又想把这些木棒恢复到截断前的状态,但忘记了初始时有多少根木棒以及木棒的初始长度。计算木棒初始时可能的最小长度。每一节木棒长度都用大于0 的整数表示。

代码:

/*

 * 木棒截断问题(递归)

 *

 * 题目:一组等长的的木棍,随机的截断,使每一段不超过50个长度单位。

 * 然后又想把这些木棒恢复到截断前的状态,但忘记了初始时有多少

 * 根木棒以及木棒的初始长度。计算木棒初始时可能的最小长度。每

 * 一节木棒长度都用大于0 的整数表示。

 *

 * 思路:假设这组木棒的总长度是M,截断后最大的长度为P,初始时可能

 *       的最小长度为L。则L>=P,M整除L。所以可以从P开始搜索L的可能

 *       值。设计一个递归函数判断L是否可能是原始木棒的长度。

 */

 

#include<stdio.h>

 

#define MAX_NUM 50 //截断后木棒的节数

 

int a[MAX_NUM];    //存放截断后各节木棒的长度

int num;           //木棒的个数

int used[MAX_NUM]={0};//木棒是否被使用,即是否以被拼接

 

//初始化a数组和num

void init()

{

     int i;

     printf("输入截断后木棒节数:\n");

     scanf("%d",&num);

     printf("输入截断后各节木棒的长度:\n");

     for(i=0;i<num;i++)

         scanf("%d",&a[i]);

}

 

//对木棒长度从大到小冒泡排序

void sort()

{

     int i,j,temp;

     for(i=0;i<num;i++)

              for(j=0;j<num-1;j++){

                       if(a[j]<a[j+1]){

                                 temp=a[j];

                                 a[j]=a[j+1];

                                 a[j+1]=temp;

                       }

              }

}

 

//判断某个长度是否可能是原始木棒的长度

//stickNum是截断后木棒总节数,unuseStickNum是未被拼接的木棒节数

//left当前剩余可拼接的长度,len正在尝试的原始木棒长度

int can(int stickNum,int unuseStickNum,int left,int len)

{

     int i;

     if(left==0 && unuseStickNum==0)

              return 1;

     if(left==0)

              left=len;

    for(i=0;i<stickNum;i++){

              if(used[i])

                       continue;

              if(a[i]>left)

                       continue;

              used[i]=1;

              if(can(stickNum,unuseStickNum-1,left-a[i],len))

                       return 1;

              used[i]=0;

     }

     return 0;

}

 

//从最大的那节木棒开始寻找可能的长度

void search()

{

     int i;

     int sum=0;

     for(i=0;i<num;i++)

              sum+=a[i];

     for(i=a[0];i<=sum;i++){

              if(sum%i!=0)

                       continue;

              if(can(num,num,i,i)){

                       printf("%d\n",i);

                       break;

              }

     }

     if(i>sum)

              printf("error\n");

}

 

void main()

{

     init();

     sort();

     search();

}

0
2
分享到:
评论

相关推荐

    浅析C语言递归算法

    ### 浅析C语言递归算法 #### 一、递归的基本概念 递归是计算机科学和编程领域中一种常见的算法和技术。递归的核心思想是在解决问题的过程中,通过将问题分解成更小规模的子问题来逐步逼近解决方案。递归算法在...

    浅析C语言递归算法.pdf

    递归算法是C语言编程中的一个重要概念,它允许函数调用自身来解决问题。本文旨在深入分析C语言中的递归算法,并为编程设计提供参考。 首先,递归算法的核心在于它能够将复杂的问题分解为相似的子问题,通过解决这些...

    浅析 语言递归

    ### 语言递归详解 #### 一、递归的基本概念 递归作为一种经典的算法,在程序设计领域占有举足轻重的地位。它不仅让程序结构更加清晰、易于理解,还能简化某些看似复杂的问题。然而,递归也有其难点所在,尤其是...

    浅析PHP递归函数返回值使用方法

    然而,正确地设计递归函数并不容易,尤其是处理好递归过程中的返回值。 #### 三、PHP递归函数案例分析 ##### 案例背景 假设我们有一个需求:编写一个递归函数,该函数接受一个整数参数 `$i`,并不断地减去4,直到 ...

    关于旅行售货商问题的剪枝递归浅析

    旅行售货商问题是高校大一计算概论课程习题集中的一个属于递归学习范畴的经典c语言问题,对于旅行售货商问题用带有剪枝的递归法进行解决,普通的递归方法会导致程序运行超时。

    数据结构中二叉树的生成及遍历非递归算法浅析.pdf

    本文着重介绍了二叉树的生成以及三种基本遍历方式的非递归算法,这些算法在数据结构和算法的学习与应用中具有重要意义。 首先,二叉树是由节点组成的有限集合,可以为空或者仅包含一个根节点和不相交的左右子树。...

    浅析python递归函数和河内塔问题

    Python递归函数是一种编程技术,它允许函数在执行过程中调用自身来解决问题。递归通常用于处理具有重复结构的问题,简化代码逻辑。在上述例子中,我们通过阶乘函数`factorial(n)`来展示了递归的基本概念。阶乘是所有...

    JavaScript递归操作实例浅析

    JavaScript递归操作是一种重要的编程技巧,它涉及到函数自身调用自身的能力,以解决复杂的问题或进行数据结构的遍历。本文将深入探讨递归的概念、实现方式以及在JavaScript中的注意事项。 首先,递归的核心原理是将...

    浅析树型数据结构中递归算法的实现.pdf

    #资源达人分享计划#

    Linux内核配置系统浅析

    ### Linux内核配置系统浅析 #### 一、配置系统的重要性及基本结构 随着Linux操作系统在各个领域的广泛应用,尤其是在嵌入式系统领域的迅速发展,越来越多的技术人员投身于Linux内核级别的开发工作。对于这些开发者...

    浅析js实现网页截图的两种方式

    【网页截图技术浅析:JS实现的两种方法】 在Web开发中,虽然网页截图并不是一个常见的需求,但当需要时,它能发挥重要的作用。本文将深入探讨两种使用JavaScript实现网页截图的技术:Canvas和SVG。 ### 1. Canvas...

    C语言中常见的几种算法浅析.pdf

    本文将浅析C语言中常见的几种算法,包括递归算法、排序算法、迭代法、打擂台法、辗转相除法等,并对其进行了详细描述和分析。 首先,递归算法是一种在函数调用自身的过程中解决问题的算法,它分为回溯和递推两个...

    linux内核浅析

    ### Linux内核浅析——内核配置系统解析 #### 核心知识点概览: 1. **内核配置系统的重要性**:随着Linux操作系统在各领域的广泛应用,尤其是嵌入式领域的快速发展,掌握内核配置系统变得至关重要。它不仅是内核级...

Global site tag (gtag.js) - Google Analytics