---
title: 基礎DP
tags: DP
robots: noindex, nofollow
langs: zh
---
# DP介紹
DP = 遞迴+記錄下曾經算過的部分
把問題轉化成遞迴問題,用陣列儲存的方式優化速度!
TopDown: 認真做遞迴,認真把傳進去的參數當作陣列的位置存放
BottomUp: 用迴圈去填完表,再查詢 (**建議**)
## 轉移
狀態: 問題本身所存在的一些性質,多數為未知的,僅有初始值是
從已知的狀態去推導未知的狀態
:warning:**初始狀態很重要**
## DP秘技的拉
1. 設定狀態
設定陣列的維度與陣列內容所表達的意義
2. 設定轉移狀態
制定如何用已知的解得出未知問題的答案
3. 制定合理的初始狀態
將足夠且合理的初始狀態預先填入陣列中
john的話DP問題就可以有條理的解決掉了 :smile:
## 例題1
### 題目敘述
:::info
爬$n$層樓梯, 每次能往上爬$1$或$2$或$3$層, 問你爬樓梯的方法數?
:::
1. 設定狀態
- $dp(n)$ 表示爬到第 $n$ 層樓梯的方法數
2. 設定轉移狀態
- 想一想之後發現,第 $n$ 層的樓梯可以從第 $n-1$ 或第 $n-2$ 或第 $n-3$ 層樓梯爬到, 所以 $dp(n) = dp(n-1)+dp(n-2)+dp(n-3)$
3. 制定合理的初始狀態
- $dp(1)$ 和 $dp(2)$ 和 $dp(3)$ 似乎不能用以前算過的答案來推知, 似乎就是初始狀態了, 所以先自己設定好初始狀態的值, $dp(1)=1,\;dp(2)=2,\;dp(3)=\{(1,1,1), (1, 2), (2, 1), (3)\}=4$
4. 所以應該可以寫成這樣
```cpp=
int dp[100000];
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];
}
```
## 優質atcoder edu **dp** contest
### 練啦哪次不練
- https://atcoder.jp/contests/dp/tasks