数组解简单多次递归

来源:互联网 发布:中博软件学院 编辑:程序博客网 时间:2024/06/02 05:31

OJ题:超级台阶
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
有一楼梯共m级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第m级,共有多少走法?

注:规定从一级到一级有0种走法。

输入
输入数据首先包含一个整数n(1<=n<=100),表示测试实例的个数,然后是n行数据,每行包含一个整数m,(1<=m<=40), 表示楼梯的级数。

输出
对于每个测试实例,请输出不同走法的数量。

一开始是用一个递推公式来求n阶台阶的走法
f(n) = f(n-1) +f(n-2)
从第4阶台阶开始,到达第n阶台阶总共有两种方法,一是从n-1阶台阶一次走一步,一是从n-2阶台阶一次走两步,而从n-2阶台阶先走一步再走一步到达的这种情况,实际上是从n-2阶台阶先走一步到达n-1阶再走一步,是属于第一种情况的
以此便可以得出上述递推式。
而n为1、2、3的情况直接求出便可。
这样便得出求走n阶台阶的方法的函数

#include <iostream>using namespace std;int f(int m){    if(i==1) return 0;    if(i==2) return 1;    if(i==3) return 2;    return f(m-1)+f(m-2);}int main(){    int s;cin>>s;    while(s--)    {        int m;cin>>m;        cout<<f(m)<<endl;    }    return 0;}

而在主函数调用时发现超时
仔细研究,觉得这个递推公式应该已经是最简单的了
虽然知道递归那里时间复杂度很高,但是发现每次调用f()函数都要进行3次判断。
刚好发现了前面的操作可以合成为一个,于是把f()函数改成

int f(int m){    if(m<=3) return m-1;    return f(m-1)+f(m-2);}

这样时间复杂度前面的系数可以变成1/3。
但是果然还是太天真了,还是递归了太多层才超的时
突然看到输入限制中,1<=m<=40
突然想到可以做一个数组,直接把每一个值的结果求出来,而因为前面的值已经求出来了,求当前第n阶的方法时,就只需要执行一次加法操作
a[n]=a[n-1]+a[n-2];
果然
修改代码后AC了。

#include <iostream>using namespace std;int main(){    int s;cin>>s;    int a[41];    a[1]=0;a[2]=1;a[3]=2;       for(int j=4;j<=40;j++)           a[j]=a[j-1]+a[j-2];    while(s--)    {        int m;cin>>m;        cout<<a[m]<<endl;    }       }

然后突然想到前两天刚开始做OJ做了一道题,一直超时,好像也可以这样求出来,于是立马回到那题

OJ题目:孪生素数问题
时间限制:3000 ms | 内存限制:65535 KB
难度:3
描述
写一个程序,找出给出素数范围内的所有孪生素数的组数。一般来说,孪生素数就是指两个素数距离为2,近的不能再近的相邻素数。有些童鞋一看到题就开始写程序,不仔细看题,咱们为了遏制一下读题不认真仔细的童鞋,规定,两个素数相邻为1的也成为孪生素数。

输入
第一行给出N表示测试数据组数。(1<=N<100)
接下来组测试数据给出m,表示找出m之前的所有孪生素数。
(1<=m<1000000)

输出
每组测试数据输出占一行,该行为m范围内所有孪生素数组数

这个问题,一开始是从3开始,遍历所有不大于m的奇数,先判断这个奇数是不是质数,如果是再判断相邻的奇数是不是质数。
判断素数需要√n的时间复杂度,总共有n/2个数要判断。
虽然不能直接相乘,但是应该和√n*n的规模差不多
而m取到最大值的时候,显然就超时

当时做这题筛选法求质数也没做出来,反而一经上题启发
直接就开始写

#include <iostream>using namespace std;int a[1000001];bool prime(int n){    if(n<=1) return false;    for(int i=2;i*i<=n;i++)       if(n%i==0)   return false;    return true;}int pri(int n){    if(prime(n)&&prime(n-2)) return 1;    else return 0;}int main(){    a[1]=0;a[2]=0;a[3]=1;    for(int i=4;i<1000001;i++)    {        a[i]=a[i-1]+pri(i);    }    int s;cin>>s;    while(s--)    {        int n;cin>>n;        cout<<a[n]<<endl;    }    return 0;}

基本操作就变成了
a[i]=a[i-1]+pri(i);

两道题共同的地方就是,规模已知,然后第n次结果与前面的结果有关联,但是如果用递归或者蛮力,会很复杂,并且每次求一个不同的n,都要重新算。那么这样的话,建立一个等规模的数组,直接用前面的值按照公式去推后面的值,应该会要好一些。

0 0
原创粉丝点击