算法力扣刷题记录 七十一【70. 爬楼梯(进阶版)】

前言

本题是记录 七十【70. 爬楼梯】的扩展题。继续。


一、题目阅读

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述

输入共一行,包含两个正整数,分别表示n, m

输出描述

输出一个整数,表示爬到楼顶的方法数。

输入示例

3 2   代表共有3个台阶,每次至多走2步。

输出示例

3 到达第3层台阶,有3种方案。

提示信息

数据范围:
1 <= m < n <= 32;

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

1 阶 + 1 阶 + 1 阶段
1 阶 + 2 阶
2 阶 + 1 阶

二、尝试实现

思路

  1. 参考说这是完全背包问题(70. 爬楼梯(进阶版)参考链接),此时还没有学背包问题怎么做,先分析题目。找状态转移公式,确定dp含义和下标含义。
  2. dp数组如果还用一维已经不够了,因为有两个参数int n代表到第几层;int m指明每步至多走多少。所以需要二维数组,dp[i][j]代表到第i层台阶,每步至多走j步,有dp[i][j]种方案
  3. 开始推导状态转移公式。
    在这里插入图片描述
    所以对应的dp数组如下:
    在这里插入图片描述
  4. 确定遍历顺序:外层循环是i,代表每一层,在第几层台阶上,从上到下;内层循环是j,代表每一列,一步最多走j个台阶,从左到右。(方向是由递推公式得来)
  5. 数组的规律有:
  • 当 j ==1时,可以直接赋值1;
  • 当j == i时,dp等于左边的前一个dp[i][j-1] +1.
  • 当 j > i时,dp等于左边的值。dp[i][j] == dp[i][j-1];
  • 当j < i 时,要同一列倒数j个数相加。
  1. 数组初始化:第一行特殊,所以初始化始终为1。
  2. 下标0行0列没有含义。

代码实现

#include <iostream>
#include <vector>
using namespace std;

int climbstair(int n,int m){
    //定义dp[i][j]数组,dp[i][j]到达第i层,可以至多爬j个台阶,有多少种方案。
    vector<vector<int>> dp(n+1,vector<int> (m+1,0));
    
    //初始化
    for(int j = 1;j <= m;j++){
        dp[1][j] = 1;
    }
    
    //遍历顺序
    for(int i = 2;i <=n;i++){//代表第几层
        for(int j = 1;j <= m;j++){
            if(j ==1) dp[i][j] = 1;
            else if(j == i) dp[i][j] = dp[i][j-1]+1;
            else if(j > i) dp[i][j] = dp[i][j-1];
            else{
                //递推公式
                for(int k = 1;k <= j;k++){
                    dp[i][j] += dp[i-k][j];
                }
            }
        }
    }
    return dp[n][m];
}
int main(){
    int n,m;
    cin>>n>>m;
    int result = climbstair(n,m);
    cout<<result<<endl;
    return 0;
}

总结

这道题目在后面背包问题学习中再来继续练习。

代码只是用动态规划五部曲完成,硬推状态转移公式,耗时较久,并没有映射到参考说的完全背包问题上。

动态规划还是渐进练习。

(欢迎指正,转载标明出处)

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值