链接:
https://www.luogu.com.cn/problem/P1255https://www.luogu.com.cn/problem/P1255
题目:
楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。
编一个程序,计算共有多少种不同的走法。
输入格式:
一个数字,楼梯数。
输出格式:
输出走的方式总数。
例:
输入:
4
输出:
5
提示:60%的数据中,N <51;
100%的数据中,0<N<5001;
思路:
这一题第一眼看是不是和斐波那契数列很相似?
首先,我们假设从第零个楼梯开始走,目前在第1个楼梯,那么我们只有一种走法;当我们在第2个楼梯,那么我们有两种走法可以走;当我们在第三个楼梯时,我们可以有3种走法(1+2)可以走;当我们在第4个楼梯时,我们有5种走法(2+3)可以走,以此类推,我们不难发现有2个以上楼梯时,我们的走法可以由前两个楼梯的走法相加求得。
那我们可以用dfs来进行搜索答案。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
long long beg, end;
long long dfs(int n) {
if (n == beg) {
return 1;
}
if (n == beg+1) {
return 2;
}
else {
return dfs(n - 1) + dfs(n - 2);
}
}
int main() {
scanf("%lld%lld", &beg, &end);
printf("%lld", dfs(end));
return 0;
}
我们很容易发现当楼梯数较大时,每一次查询上一个楼梯或上两个楼梯都要重新计算一遍,这导致运行时间远远超过了规定时间(TLE)。那么我们应该将dfs算法改进为更快的记忆化搜索算法。
我们可以定义一个数组用于存储到达每一个楼梯的走法数量。
我们定义一个数组,让第1和2个楼梯的走法设为1和2,那我们可以使用一遍循环(时间复杂度O(N))求得最终答案。假设我们要求第i个楼梯的走法,我们让数组中i-1个楼梯的走法和i-2个楼梯的走法求和并且赋给i个楼梯的走法。
我们再次提交代码,发现还是WA了。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
long long end;
long long arr[5005] = { 0 };
int main() {
scanf("%lld", &end);
arr[1] = 1;
arr[2] = 2;
for (int i = 3; i <= end; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
printf("%lld", arr[end]);
return 0;
}
那可能是因为路径数比整形的最大值还大了。那应该使用高精度来存储数据了。
我们定义一个足够大的二维数组,用于存储每一位数字。
我们设置一个函数叫Sum用于高精度运算。让数组低位为数字低位,数组高位为数据高位。让flag首先等于0,在最后等于该数字的十位,让每位相加后对10取余。以此我们实现了高精度运算。
int arr[5005][5005]={0};
//X表示N-1,Y表示N-2
void Sum(int x, int y) {
for (int i = 0, flag = 0; i < 5005; i++) {
arr[x + 1][i] = arr[x][i] + arr[y][i] + flag;
flag = 0;
if (arr[x + 1][i] > 9) {
arr[x + 1][i] %= 10;
flag = 1;
}
}
return;
}
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
int n;
int arr[5005][5005] = { 0 };
//X表示N-1,Y表示N-2
void Sum(int x, int y) {
for (int i = 0, flag = 0; i < 5005; i++) {
arr[x + 1][i] = arr[x][i] + arr[y][i] + flag;
flag = 0;
if (arr[x + 1][i] > 9) {
arr[x + 1][i] %= 10;
flag = 1;
}
}
return;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
if (i <= 2) {
arr[i][0] = i;
}
else {
Sum(i - 1, i - 2);
}
}
for (int i = 5004,flag=0; i >= 0; i--) {
if (!arr[n][i] && !flag) {
continue;
}
printf("%d", arr[n][i]);
flag = 1;
}
return 0;
}
在最后,给大家留一个问题,如何只使用三个一维数组来计算目标楼梯的走法?如果大家有想法,可以将想法发在评论区,我会和大家一起讨论。
如果我的文章对你有所帮助,可以给萌新一个大大的点赞和关注吗。