怎样设计递归算法

Posted on 2007-05-27 16:10  少林  阅读(4622)  评论(2编辑  收藏  举报
      在实际编程中,有许多定义或者问题本身就具有递归性质.所以我们顺其自然就想到用递归来解决.这样不仅代码少,而且结构清晰.但是问题是我们应该怎样设计递归呢?这确实一个问题,由于许多问题并不是很明显的表现出递归的关系,所有很大一部分需要我们进行推导,从而得出递归关系,有了递归关系,编写代码就相对的比较简单了.首先,我们了解递归算法的特点,所谓的递归,就是把一个大型的复杂的问题层层的转化为一个与原问题相似的较少规模的问题,在逐步求解小问题后,再返回得到较大问题的解.由于递归只需要少量的步骤就可描述解题过程中所需要的多次重复计算,所以大大的减少了代码量.递归算法设计的关键在于,找出递归方程和递归终止条件(边界条件).递归关系就是使问题向边界条件转化的过程.因此,递归关系必须能使问题越来越简单,规模越小.
      因此,递归算法设计,通常有以下3个步骤:
      (1)分析问题,得出递归关系.
      (2)设置边界条件,控制递归.
      (3)设计函数,确定参数.

      好了,说了,这么多,我相信大家迫不及待要大显身手一番了吧,现在我们就通过一个具体的问题来前面阐述递归算法的设计过程.
      问题  整数划分的问题
             对于一个整数n的划分,就是把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
      现在问题是,给一个n求他的所以划分.
      这个问题初看,很难找出大规模问题与小规模问题之间的关系,我们注意了,对于上面的第一行,所以加数不超过6,第2行,所以加数不超过5,.................第6行所以加数不超过1.因此,我们可以定义一个q(n,m)的函数,表示 n所以加数不超过m的划分数目.所以n的划分总数目可以表示为q(n,n).那我们怎样才能把找出q(n,n)的递归关系呢?
      很显然,我们可以立即得到以下关系,
        (1)q(n,n)=q(n,n-1)+1;
      所以问题规模变小,但是我们很不能根据这个关系转化为更小的问题,所以我们主要考虑这种情况:q(n,m)<其中m<n>,怎样把这中情况分解呢.我们尝试的把q(n,m)变为q(n,m-1);我们惊奇的发现,只要把q(n,m-1)加上包含加数m的项就等于q(n,n).即q(n,m)=q(n,m-1)+包含m加数的表达式数.例如m=4,我们可以把q(n,4)=q(n,3)+2(包含4加数的表达使有两个:4+2,4+1+1).而我们发现,包含4的表达可以转化为q(n-m,n-m)(想想?);所以的递归关系式就出来了.
      (2)q(n,m)=q(n,m-1)+q(n-m,n-m);
      接下来就是找边界条件了,我们知道当n=1时,q(n,n)=1.当m =1时,q(n,m)=1;有了边界条件,我们递归基本上完成了,编写代码如下:
      
#include<stdio.h>
int f(int n,int m)
{
    
if(n==1||m==1)
    
{
        
return 1;
    }

    
else if(n==m)
    
{
        
return f(n,n-1)+1;
    }

    
else if(n<m)
    
{
        
return f(n,n);
    }

    
else if(n>m)
    
{
        
return f(n,m-1)+f(n-m,m);
    }

}

main()
{
    
int n,sum;
    scanf(
"%d",&n);
    sum
=f(n,n);
    printf(
"%d\n",sum);
}

Copyright © 2024 少林
Powered by .NET 8.0 on Kubernetes