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,都要重新算。那么这样的话,建立一个等规模的数组,直接用前面的值按照公式去推后面的值,应该会要好一些。