Dynamic Programming
動態規劃
拿小問題的解推到大問題的解
小問題就用手算(X
DP 的陣列,也會被稱為 DP 表格
例如上面的 dp[i] 就是一種
也有人會用 dfs+unordered_map/map
但是僅限於特殊情況,因為遞迴常數很大
問題的最佳解可以從子問題的最佳解得到
不能有迴圈
總時間 = \(\displaystyle\sum_{狀態} 轉移量\)
剛開始通常每個狀態時間恆定,所以可以改成
狀態數量 \(\times\) 每個狀態的轉移量
題單在這,現在下課
你看到右邊藍藍的箭頭了嗎
看到了嗎
真的看到了嗎
假設 dp[i] 表示青蛙從左邊開始跳,剛好跳到第 i 個石頭的最小花費
dp[i] 會跟那些東西有關?
考慮上一個跳過來的地方是誰,只有 i-1 與 i-2 兩種可能
那麼 dp[i] = min(dp[i-1] + abs(h[i] - h[i-1]), dp[i-2] + abs(h[i] - h[i-2]))
邊界條件 dp[0] = 0
複雜度 O(n)
定義方式同左
一樣是考慮 dp[i] 會跟那些東西有關
用一個迴圈掃過前 k 個更新 DP 值
複雜度 O(nk)
dp[i][j] = 考慮到第 i 個,第 i 個剛好選的是 j 的最大值
因為第 i 個要選誰只跟前一個是誰有關
轉移式 dp[i][j] = max(dp[i-1][],dp[i-1][]) + a[i]
複雜度 O(n)
這題的 w 比較大,但是 v 比較小
不能用 O(nw) 的做法
反著考慮:假設當前已經拿了總價值恰好為 v 的東西,最小重量是多少
轉移方式類似,邊界條件是 dp[0] = 0, dp[i] = inf
經典題
叫做 longest common subsequence (LCS)
設 dp[i][j] = s 的前 i 項與 t 的前 j 項的 LCS 是多少
如果 s[i] == t[j],那麼在 dp[i-1][j-1] 後面增加一個字元 s[i] 一定是最好的
否則 dp[i][j] = max(dp[i-1][j], dp[i][j-1])
複雜度 O(ST)
dp[i][j] 表示走到 (i,j) 點有幾種走法
如果走不到就設成 0
dp[i][j] = ...
考慮 dp[i][j][k] 表示有 i 個 1,j 個 2,k 個 3
轉移可能會有自環 -> 移項
後面還有但我懶得放了
CSES 也值得去刷