ACwing—跳台阶(bfs+dp+递归+记忆化搜索算法)
题目描述
 一个楼梯共有 n级台阶,每次可以走一级或者两级,问从第0级台阶走到第n级台阶一共有多少种方案。
输入格式
共一行,包含一个整数 n
输出格式
共一行,包含一个整数,表示方案数。
数据范围
1≤n≤45
 
 样例
 
 
输入样例:
5
 输出样例:
8
代码一(暴力的BFS):
#include <stdio.h>
int climbStairs(int x) {
     
	if (x == 1) {
		return 1;
	}
	else if (x == 2) {
		return 2;
	}
	else {
		return climbStairs(x - 1) + climbStairs(x - 2);
	}
  
}
int main() {
	int n;
	printf("请输入楼梯的阶数:");
	scanf("%d", &n);
	int ways = climbStairs(n);
	printf("%d 阶楼梯一共有 %d 种跳法。\n", n, ways);
	return 0;
}

代码过程分析:
        climbStairs(5)
         /        \
        /          \
   climbStairs(4)  climbStairs(3)
    /      \          /     \
   /        \        /       \
climb(3)  climb(2) climb(2) climb(1)
  /  \       |        |        |
 /    \      |        |        |
c(2) c(1)   2        2        1
 |     |
 2     1climbStairs(5)
= climbStairs(4) + climbStairs(3)
= [climbStairs(3) + climbStairs(2)] + [climbStairs(2) + climbStairs(1)]
= [ [climbStairs(2) + climbStairs(1)] + 2 ] + [2 + 1]
= [ [2 + 1] + 2 ] + 3
= [3 + 2] + 3
= 5 + 3
= 8步骤分解
-  climbStairs(5)-  调用 climbStairs(4)和climbStairs(3),等待它们的返回值。
 
-  
-  计算 climbStairs(4):-  调用 climbStairs(3)和climbStairs(2),等待返回值。
-  计算 climbStairs(3):-  调用 climbStairs(2)和climbStairs(1)。-  climbStairs(2)返回 2(基准条件)。
-  climbStairs(1)返回 1(基准条件)。
 
-  
-  合并结果: 2 + 1 = 3。
 
-  
-  计算 climbStairs(2):-  直接返回 2(基准条件)。 
 
-  
-  合并结果: 3 + 2 = 5。
-  climbStairs(4)返回 5。
 
-  
-  计算 climbStairs(3):-  调用 climbStairs(2)和climbStairs(1)。-  climbStairs(2)返回 2。
-  climbStairs(1)返回 1。
 
-  
-  合并结果: 2 + 1 = 3。
-  climbStairs(3)返回 3。
 
-  
-  合并最终结果: -  climbStairs(5) = climbStairs(4) + climbStairs(3) = 5 + 3 = 8。
-  对结果取模 1e9 + 7(因8 < 1e9 + 7,结果仍为 8)。
 
-  
代码二(记忆化搜索):
#include <stdio.h>
const int N=45;
int mem[N];
int climbStairs(int x) {
     
    if(mem[x]) return mem[x];
    
    int sum=0;
    
	if (x == 1) {
		sum=1;
	}
	else if (x == 2) {
		sum=2;
	}
	else {
		sum=climbStairs(x - 1) + climbStairs(x - 2);
	}
    mem[x]=sum;
    return sum;
 
}
 
int main() {
	int n;
	printf("请输入楼梯的阶数:");
	scanf("%d", &n);
 
	int ways = climbStairs(n);
	printf("%d 阶楼梯一共有 %d 种跳法。\n", n, ways);
 
	return 0;
}
代码过程分析:
        climbStairs(5) → 8
         /           \
        /             \
   climbStairs(4) →5  [climbStairs(3) →3 (cached)]
    /        \               /     \
   /          \             /       \
climb(3)→3  climb(2)→2  climb(2)→2  climb(1)→1 (cached)
  /    \
 /      \
c(2)→2  c(1)→1 (cached)记忆化数组 mem 的最终状态
索引1	2	3	4	5
值	1	2	3	5	8
-  步骤分解
-  初始化全局数组 mem
 所有元素初始值为0。
-  调用 climbStairs(5)-  检查 mem[5]是否为0(初始为0),进入计算分支。
-  递归调用 climbStairs(4) + climbStairs(3)。
 
-  
-  计算 climbStairs(4)-  mem[4] = 0,进入计算分支。
-  递归调用 climbStairs(3) + climbStairs(2)。-  计算 climbStairs(3):-  mem[3] = 0,进入计算分支。
-  递归调用 climbStairs(2) + climbStairs(1)。-  计算 climbStairs(2):-  mem[2] = 0,赋值sum = 2,存入mem[2] = 2,返回2。
 
-  
-  计算 climbStairs(1):-  mem[1] = 0,赋值sum = 1,存入mem[1] = 1,返回1。
 
-  
 
-  
-  sum = 2 + 1 = 3,存入mem[3] = 3,返回3。
 
-  
-  计算 climbStairs(2):-  mem[2] = 2(已缓存),直接返回2。
 
-  
 
-  
-  sum = 3 + 2 = 5,存入mem[4] = 5,返回5。
 
-  
-  计算 climbStairs(3)(在climbStairs(5)中)-  mem[3] = 3(已缓存),直接返回3。
 
-  
-  合并结果 -  climbStairs(5) = 5 (climbStairs(4)) + 3 (climbStairs(3)) = 8。
-  存入 mem[5] = 8,最终返回8。
 
-  
-  记忆化存储:每个 climbStairs(x)的结果存入mem[x],避免重复计算。
-  递归逻辑: -  climbStairs(x) = climbStairs(x-1) + climbStairs(x-2)(斐波那契数列)。
-  基准条件: x=1返回1,x=2返回2。
 
-  
代码三(递归(dp)):
#include <stdio.h>
const int N=45;
int f[N];
int n;
int main() {
	scanf("%d",&n);
    f[1]=1,f[2]=2;
	if(n==1||n==2){
        printf("%d",f[n]);
        return 0;
    }
	for(int i=3;i<=n;i++){
        f[i]=f[i-1]+f[i-2];
    }
    printf("%d",f[n]);
	return 0;
}
