算法之浅谈递归与分治

递归?首先明白何为递归。

递归有两个要点:1.自己直接或者间接地调用自己。2.必须有递归出口。

优点:容易设计算法,易于思考。

缺点:时间复杂度过高,运用递归时,注意数据规模。

递归特点:

1、问题P的描述涉及规模P(n);  2、规模变小之后,问题的性质不会发生变化;    3、问题有解决出口

样例分析:

一、阶乘问题    二、汉诺塔问题    三、全排列问题   

四、最大公约数和最小公倍数        五、整数划分问题


问题一解答,递归完成n!f(n)=n*f(n-1) n!=0  if(n==0) f(n)=1;

int f(int n){//求n!
    if(n==0) return 1;
    else if(n<0) return n*f(n+1);
    else return n*f(n-1);
}


问题二描述:

有X,Y,Z三个塔柱,X上有n个盘子,从小到大盘子一次增大,求出把盘子移动到Z上的最小步数。

要求:1.一次移动一个     2.任何时刻,要求大的盘子都不能在小的盘子上面。Y作为辅助塔柱


问题分析:设置函数Hanoi(X,Y,Z,n);

1,若要吧把第n个盘子移动到Z上,首先把X上的前n-1个盘子移动到Y塔柱上,(此时Z可以作为辅助塔柱)

此时函数为Honoi(X,Z,Y,n-1);  Move X----->Z(1次)

2、把Y上的全部盘子移动到Z上 ,函数为Hanoi(Y,X,Z,n-1);

int sum=0;//每次运行时,置0
void Hanoi(char X,char Y,char Z,int n){
   if(n>0){
        Hanoi(X,Z,Y,n-1);
        ++sum;
        Hanoi(Y,X,Z,n-1);
   }

}


问题三:

求数组的全排列或者求数组a的第k到第n个元素的全排列。

深度搜索,

#include
#include
#include
using namespace std;
void range(int a[],int k,int n){
    if(k==n) {
        for(int i=1;i<=n;i++){
            printf("%d",a[i]);
        }
        printf("\n");
    }
    for(int i=k;i<=n;i++){
        swap(a[k],a[i]);
        range(a,k+1,n);
        swap(a[k],a[i]);
    }

}
int main()
{
    int a[10]={0,1,2,3,4,5,6,7,8,9};
    range(a,1,4);
    return 0;
}

问题四:

题目描述:将一个整数n表示成一系列正整数之和。n=n1+n2+......+nk,其中5=1+4; 5=4+1是一种,

正整数n的不同划分个数为正整数的划分数,记做P(n).

1、题解,在正整数所有不同划分中,将最大加数n1不大于m的划分记做q(n,m);

(1)、q(n,1)=1; n>=1 即 n=1+1+...+1

(2)、q(n,m)=q(n,n) m>=n; 最大加数不能大于n,q(1,m)=1

(3)、q(n,n)=1+q(n,n-1) 最大加数等于n和小于n的所有个数

(4)、q(n,m)=q(n,m-1)+q(n-m,m); 最大加数等于m和小于m-1的划分个数

代码如下:

int q(int n,int m){
    if((n<1)||(m<1)) return 0;
    if((n==1)||(m==1)) return 1;
    if(n     if(n==m) return q(n,m-1)+1;
    return q(n,m-1)+q(n-m,m);
}
int qq(int n){
    if(n<1) return 0;
    if(n==1) return 1;
    else return qq(n-1)+1;
}

进阶问题:求出正整数n的所有划分并打印,

例如:

n=2   :2=1+1

n=3   :3=1+2

            =1+1+1

n=4   :4=1+3

            =1+1+2

            =1+1+1+1

            =2+2

n=7   :7=1+6

            =1+1+5

            =1+1+1+4

            =1+1+1+1+3

            =1+1+1+1+1+2

            =1+1+1+1+1+1+1

            =1+1+1+2+2

            =1+1+2+3

            =1+2+4

            =1+3+3

            =2+5

            =2+2+3

            =3+4

题解:可以用数组a存储完成n的一种划分,分析n=7时,可以按a[1]分类(即以1开头,按划分的第一的数分类),可得到a[1]=[1,n/2],共n/2大类,对于每一类划分都有a[1]=i; a[2]=n-i; 然后从k=2,继续拆分a[k],a[k]能否拆分取决于a[k]/2是否大于a[k-1].递归过程中的参数,指向的a[k]的下标k

代码:

#include
#include
#define MOD 1000000007
using namespace std;
void  split(int t,int n){
    printf("%d=",n);
    for(int i=1;i<=t;i++){
        if(i==1) printf("%d",a[i]);
        else printf("+%d",a[i]);
    }
    printf("\n");
    int j,l;
    j=t; l=a[j];
    for(int i=a[j-1];i<=l/2;i++){
        a[j]=i; a[j+1]=l-i;
        split(j+1,n);
    }
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n/2;i++){
        //cout<<"      "<         a[1]=i; a[2]=n-i; split(2,n);
    }

    return 0;
}

备注:笔者水平有限,希望各路大牛不吝指教。于2014年10月7日  22:22






你可能感兴趣的:(小喵算法经)