P1255 数楼梯 题解
作者:互联网
题目描述
楼梯有 \(N\) 阶,上楼可以一步上一阶,也可以一步上二阶。
编一个程序,计算共有多少种不同的走法。
输入格式
一个数字,楼梯数。
输出格式
输出走的方式总数。
解决
1. 递归的方法
有 \(1\) 阶楼梯时,输出 1
;有 \(2\) 阶时,输出 2
;否则,递归 pa(n-2)+pa(n-1)
。
这种方法十分好理解,但不能 AC 。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
long long pa(int n){
if(n==1){
return 1;
}else if(n==2){
return 2;
}else{
return pa(n-1)+pa(n-2);
}
}
int main(){
cin>>n;
cout<<pa(n);
}
这种方法可以得到 \(50\) 分:
上图中递推造成 TLE,是因为函数一遍又一遍地调用自身,耗费了大量时间。
那么有没有耗时较少的方法呢?我们不难想到递推。
2. 纯递推的方法
我们试着列举各种阶数和对应的走法数:
比如,在 \(N=1\) 时,只有一种走法:上 \(1\) 阶。
在 \(N=2\) 时,有两种走法:11 和 2 。
在 \(N=3\) 时,有三种走法:111、12 和 21 。
列举更多的数字,得到下表:
阶数 \(N\) | 走法数 |
---|---|
1 | 1 |
2 | 2 |
3 | 3 |
4 | 5 |
5 | 8 |
6 | 13 |
7 | 21 |
这个表格中的走法数神似斐波那契数列,只是第二项变成了 \(2\),由此写出:
s[1]=1
;s[2]=2
;s[n]=s[n-1]+s[n-2]
(\(n>2\))
由此得到代码:
#include<bits/stdc++.h>
using namespace std;
long long go[1010]={1,2};
int n;
int main(){
cin>>n;
for(int i=2;i<n;i++){
go[i]=go[i-1]+go[i-2];
}
cout<<go[n-1];
return 0;
}
可是这种方法依然不能 AC:
出现了两个 WA 和 RE,为什么?我们尝试输入本题的数据范围 \(5000\) ,输出了:
-8190626429588521950
这显然是得出的走法数超出了 long long
的范围。所以还得用高精度。
3. 递推+高精度的方法
利用高精度加法即可。
直接上代码:
#include<bits/stdc++.h>
using namespace std;
int n; // 楼梯阶数
int a[5002][5002]; // 能过即可,不要开太大
int l=1; // l 标记长度
int g_sum(int c){ // 负责高精度加法
for(int i=1;i<=l;i++){ // 两数按位相加(这里必须用 <=1 ,否则 20 分)
a[c][i]=a[c-1][i]+a[c-2][i];
}
for(int i=1;i<=l;i++){
if(a[c][i]>9){ // 如果某一位上两位数
a[c][i+1]+=a[c][i]/10; // 模拟进位
a[c][i]=a[c][i]%10;
}
if(a[c][l+1]){ // 扩充容量
l++;
}
}
}
int main(){
a[1][1]=1; // 初始化 (等同于go[1]=1)
a[2][1]=2; // 等同于go[2]=2
cin>>n;
for(int i=3;i<=n;i++){
g_sum(i); // 相加即可
}
for(int i=l;i>0;i--){
cout<<a[n][i]; // 倒着输出结果
}
return 0;
}
今天,你 AC 了吗?
附上做题过程(惨不忍睹):
标签:P1255,走法,int,题解,long,pa,楼梯,递推 来源: https://www.cnblogs.com/liujimingblog/p/16131554.html