P10250 [GESP样题 六级] 下楼梯

记录80

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
long long dp[65];
int main(){
	int n;
	cin>>n;
	dp[1]=1,dp[2]=2,dp[3]=4;
	for(int i=4;i<=n;i++) dp[i]=dp[i-1]+dp[i-2]+dp[i-3];
	cout<<dp[n];
	return 0;
} 

题目传送门https://www.luogu.com.cn/problem/P10250


突破口

顽皮的小明发现,下楼梯时每步可以走 1 个台阶、2 个台阶或 3 个台阶。现在一共有 N 个台阶,你能帮小明算算有多少种方案吗?


思路

🔍 一、题目思路分析

1. 问题本质:爬楼梯变种(三步可达)
  • 小明在第 0 级台阶,要走到第 N
  • 每次可以走 1 步、2 步 或 3 步
  • 问:有多少种不同的走法?

这是经典的 动态规划(DP) 问题,是"斐波那契数列"的扩展。


2. 状态定义

dp[i] 表示走到第 i 级台阶的方案数。

3. 状态转移方程

要到达第 i 级,最后一步可能是:

  • i−1 走 1 步
  • i−2 走 2 步
  • i−3 走 3 步

所以:

dp[i]=dp[i−1]+dp[i−2]+dp[i−3]dp[i]=dp[i−1]+dp[i−2]+dp[i−3]

4. 初始条件(边界)
  • dp[0] = 1(站在地面,1 种方案:不动)
    但本题从 N≥1 开始,且样例给出:
    • N=1 → 1 种(1)
    • N=2 → 2 种(1+1, 2)
    • N=3 → 4 种(1+1+1, 1+2, 2+1, 3)

所以直接初始化:

  • dp[1] = 1
  • dp[2] = 2
  • dp[3] = 4

✅ 验证 N=4

  • dp[4] = dp[3] + dp[2] + dp[1] = 4 + 2 + 1 = 7 ✅(符合样例)

代码分析

✅ 代码逐行解释

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
long long dp[65];
  • 引入标准库
  • 定义 dp 数组,大小 65(因为 N ≤ 60,留余量)
  • 使用 long long:防止结果溢出(N=60 时答案很大)
cpp 复制代码
int main(){
    int n;
    cin >> n;
  • 读入台阶总数 n
cpp 复制代码
    dp[1] = 1, dp[2] = 2, dp[3] = 4;
  • 初始化前三个值(根据实际走法枚举得出)
cpp 复制代码
    for(int i = 4; i <= n; i++)
        dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
  • 从第 4 级开始,按递推公式计算
  • 时间复杂度:O(n),空间复杂度:O(n)
cpp 复制代码
    cout << dp[n];
    return 0;
}
  • 输出走到第 n 级的方案总数

🧪 样例验证

样例 1:n = 4
  • dp[4] = 4 + 2 + 1 = 7
样例 2:n = 10
  • 依次计算:
    • dp[4]=7
    • dp[5]=13
    • dp[6]=24
    • dp[7]=44
    • dp[8]=81
    • dp[9]=149
    • dp[10]=274

✅ 总结

要点 说明
模型 三阶线性递推(类斐波那契)
状态转移 dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
初始值 dp[1]=1, dp[2]=2, dp[3]=4
数据类型 long long 防止溢出(N=60 时约 10¹² 量级)
复杂度 O(n) 时间,O(n) 空间

补充

在动态规划(DP)中,边界条件(或称初始状态、base case)是整个递推的起点。如果边界处理错误,即使状态转移方程正确,结果也会全错。

下面从 通用原则 + 常见场景 + 实战技巧 三方面讲解如何正确处理 DP 的边界条件。


一、核心原则:"最小不可再分的子问题"

边界条件对应的是问题规模最小、无需递推就能直接得出答案的情况

✅ 问自己:

"当 n = 0、1、2 ... 时,答案是多少?能否手动枚举?"


二、常见 DP 类型与边界处理方法

1. 线性递推型(如爬楼梯、斐波那契)

  • 问题f(n) = f(n-1) + f(n-2) + ...
  • 边界:根据题意手动计算前几项
题目 边界设置 说明
爬楼梯(1/2步) dp[0]=1, dp[1]=1dp[1]=1, dp[2]=2 取决于是否定义 dp[0]
本题(1/2/3步) dp[1]=1, dp[2]=2, dp[3]=4 直接枚举小规模情况
斐波那契 dp[1]=1, dp[2]=1 题目定义

🔑 技巧:优先按题目输入范围的最小值来设边界(如 N≥1,则从 dp[1] 开始)


2. 网格路径型(如走格子)

  • 状态dp[i][j] 表示走到 (i,j) 的方案数
  • 边界:第一行、第一列(只能沿一个方向走)
cpp 复制代码
// 无障碍
for (int i=1; i<=n; i++) dp[i][1] = 1;
for (int j=1; j<=m; j++) dp[1][j] = 1;
  • 有障碍 :若某格是障碍,则 dp[i][j] = 0,且后续路径无法通过它

⚠️ 注意:起点是否合法?

如果 (1,1) 是障碍 → 整个答案为 0


3. 背包问题

  • 01 背包 :cpp

    cpp 复制代码
    dp[0][*] = 0;   // 0 个物品,价值为 0
    dp[*][0] = 0;   // 容量为 0,装不下
  • 完全背包:类似,但注意初始化是否允许"恰好装满"

🔑 关键:dp[0][v] 的含义要明确(选 0 个物品时的最大价值)


4. 区间 DP(如石子合并)

  • 边界 :长度为 1 的区间cpp

    cpp 复制代码
    for (int i=1; i<=n; i++) dp[i][i] = 0; // 合并一个堆,代价为 0

三、处理边界的实用技巧

✅ 技巧 1:从"空状态"开始思考

  • 例如:爬楼梯中,dp[0] = 1 表示"站在地面,有 1 种方式(什么都不做)"
  • 这能让递推更统一(dp[2] = dp[1] + dp[0]

但注意:题目是否允许 n=0? 若输入保证 n≥1,可不设 dp[0]


✅ 技巧 2:手动枚举小数据验证边界

  • n=1,2,3 手动算出答案
  • 看你的 dp[1], dp[2], dp[3] 是否匹配

例:本题中 N=1 → 1 种;N=2 → 2 种;N=3 → 4 种 → 直接赋值


✅ 技巧 3:数组下标对齐问题

  • 有些题用 dp[0] 表示第 1 个元素,有些用 dp[1]
  • 建议 :让 dp[i] 直接对应"第 i 个"(如台阶 i、第 i 个物品),避免混淆

✅ 技巧 4:警惕"非法状态"

  • 如本题中的"偶行列禁区",某些 dp[i][j] 应强制为 0

  • 在初始化或转移时显式处理:

    cpp 复制代码
    if (isForbidden(i, j)) dp[i][j] = 0;
    else dp[i][j] = dp[i-1][j] + dp[i][j-1];

✅ 技巧 5:使用足够大的数组,避免越界

  • 比如 N≤60,开 dp[65] 而不是 dp[61],防止 i-3 越界
  • 或者在循环中控制起始点(如从 i=4 开始)

四、总结:处理边界四步法

  1. 理解状态定义dp[i] 到底表示什么?
  2. 找出最小问题:n=0,1,2... 时答案是多少?
  3. 手动验证:用样例或小数据检查边界值
  4. 统一处理非法状态:障碍、禁区、不可达等设为 0 或 -∞

🎯 一句话记住:

边界条件 = 递推无法覆盖的最小情况 + 非法状态的显式处理

掌握这一点,DP 的正确率会大幅提升!

相关推荐
小范自学编程1 小时前
算法训练营 Day27 - 贪心算法part01
算法·贪心算法
码农三叔1 小时前
(11-4-02)完整人形机器人的设计与实现案例:机器人跳跃
人工智能·算法·机器人·人机交互·人形机器人
xiaoye-duck2 小时前
深入解析 STL 优先级队列:从原理到实战
c++·算法·stl
蜕变的小白2 小时前
数据结构:排序算法与哈希表
数据结构·算法·哈希算法
承渊政道2 小时前
C++学习之旅【C++继承概念指南与核心内容介绍】
c语言·开发语言·c++·笔记·学习·visual studio
_OP_CHEN2 小时前
【算法基础篇】(六十一)SG 函数通关指南:博弈论通用解法,从原理到实战秒杀各类 ICG 游戏
算法·蓝桥杯·c/c++·博弈论·acm/icpc·sg函数·有向图游戏
We་ct2 小时前
LeetCode 2. 两数相加:链表经典应用题详解
前端·算法·leetcode·链表·typescript
If using 10 days2 小时前
multiprocessing:创建并管理多个进程
python·算法
会周易的程序员2 小时前
openplc runtime v4 安全
网络·c++·物联网·websocket·安全·https·ssl