--- ###### tags: `2020 師大附中校隊培訓` --- # 基礎動態規劃 ## 2020 師大附中校隊培訓 #### joylintp #### 10.27.2020 --- ## 用子問題的解算出大問題的答案 --- ## 走樓梯 有 $N$ 階樓梯, 每次可以走 1 階或 2 階, 求走完 $N$ 階樓梯的方法數除以 $10^9+7$ 的餘數 ---- ### 除以 $10^9+7$ 的餘數 * $(a+b)\ \%\ c=(a\ \%\ c+b\ \%\ c)\ \%\ c$ * $(a-b)\ \%\ c=(a\ \%\ c-b\ \%\ c + c)\ \%\ c$ * $(a\times b)\ \%\ c=(a\ \%\ c\times b\ \%\ c)\ \%\ c$ * $(\frac{a}{b})\ \%\ c=(a \times b^{c-2})\ \%\ c$ ($c$ 為質數) (非質數除法需使用擴展歐幾里得) ---- 令 $dp_i$ 為走 $i$ 階的方法數 $dp_i= \begin{cases} 1 & ,0 \le i \le 1 \\ dp_{i-1} + dp_{i-2} & ,i \ge 2 \end{cases}$ --- ## 青蛙 1 ### AtCoder Educational DP Contest pA 有 $N$ 顆石頭,第 $i$ 顆石頭的高度為 $h_i$, 目前青蛙停在第 1 顆石頭上 當青蛙停在第 $i$ 顆石頭上時, 可以跳到第 $j\ (i+1 \le j \le i+2)$ 顆石頭, 花費的體力為 $|h_i-h_j|$ 求青蛙跳到第 $N$ 顆石頭需要花費的體力總和最小值 ---- 令 $dp_i$ 為跳到第 $i$ 顆石頭時要花費的最少體力 $dp_i= \begin{cases} 0 & ,i=1 \\ |h_1-h_2| & ,i = 2 \\ min(dp_{i-2} + |h_i-h_{i-2}|, \\ dp_{i-1} + |h_i-h_{i-1}|) & ,i>2 \end{cases}$ 時間複雜度 $O(N)$ --- ## 青蛙 2 ### AtCoder Educational DP Contest pB 有 $N$ 顆石頭,第 $i$ 顆石頭的高度為 $h_i$, 目前青蛙停在第 1 顆石頭上 當青蛙停在第 $i$ 顆石頭上時, 可以跳到第 $j\ (i+1 \le j \le min(N, i+K))$ 顆石頭, 花費的體力為 $|h_i-h_j|$ 求青蛙跳到第 $N$ 顆石頭需要花費的體力總和最小值 ---- 令 $dp_i$ 為跳到第 $i$ 顆石頭時要花費的最少體力 $dp_i= \begin{cases} 0 & ,i=1 \\ |h_1-h_2| & ,i = 2 \\ min\{dp_{i-j} + |h_i-h_{i-j}|\ |\\\ 1 \le j \le min(i,K)\} & ,i>2 \end{cases}$ 時間複雜度 $O(NK)$ --- ## 假期 ### AtCoder Educational DP Contest pC 有 $N$ 天的假期 每天可以選游泳、爬山、在家其中一個, 第 $i$ 天做這些事分別可以得到 $a_i,b_i,c_i$ 的滿足度, 求在不連續兩天選一樣的情況下,可能的總滿足度最大值 ---- 令 $dp_{ij}$ 為第 $i$ 天做第 $j$ 件事時最高的滿足度 $dp_{i0}= \begin{cases} a_1 & ,i=1 \\ max(dp_{i-1\ 1}, dp_{i-1\ 2}) + a_i& ,i > 1 \end{cases}$ 剩餘兩活動同理,答案為 $max(dp_{n\ 0}, dp_{n\ 1}, dp_{n\ 2})$ 時間複雜度 $O(N)$ --- ## 01 背包問題 有 $N$ 樣物品, 每個物品有自己的價值 $p_i$ 和重量 $w_i$ 現在有一個耐重 $k$ 的背包, 問在所有物品只能選擇全放進背包或全不放進背包的情況下, 背包內的物質總價值最高是多少? ---- ### 重量 ### AtCoder Educational DP Contest pD ```cpp= for (int i = 1; i <= N; i++) { int w, v; cin >> w >> v; for (int j = 0; j < w; j++) dp[i][j] = dp[i - 1][j]; for (int j = W; j - w >= 0; j--) dp[i][j] = max(dp[i - 1][j - w] + v, dp[i - 1][j]); } int ans = 0; for (int i = 0; i <= W; i++) ans = max(ans, dp[N][i]); ``` 時間複雜度 $O(NW)$ ---- ### 價值 ### AtCoder Educational DP Contest pE ```cpp= for (int i = 1; i <= 100000; i++) dp[i] = 1e18; int sum = 0; for (int i = 1; i <= N; i++) { int w, v; cin >> w >> v; sum += v; for (int j = sum; j >= v; j--) dp[j] = min(dp[j], dp[j - v] + w); } for (int i = sum; i >= 0; i--) if (dp[i] <= W) cout << i << '\n', exit(0); ``` 時間複雜度 $O(N\ \Sigma v)$ --- ## 最長共同子序列(LCS) ---- ### 子序列 字串 $S'$ 為字串 $S$ 的子序列若 $S'$ 可以透過刪除 $S$ 中若干字元得到 `S = "ABCBDEAC"` `S` 的子序列: `"ABC"`、`"AAC"`、`""` 不是 `S` 的子序列: `"DCBA"`、`"F"` 最長共同子序列即為兩字串共同子序列中長度最長者 ---- 令 $dp_{ij}$ 為考慮第一個字串前 $i$ 個字元與第二個字串前 $j$ 個字元的最長共同子序列 $dp_{ij}= \begin{cases} 0 & ,i=0\ or\ j=0 \\ dp_{i-1\ j-1} + 1 & ,i > 0,\ j > 0,\ S[i] = T[j] \\ max(dp_{i-1\ j-1}, dp_{i-1\ j}, dp_{i\ j-1}) & ,i > 0,\ j > 0,\ S[i] \ne T[j] \end{cases}$
{"metaMigratedAt":"2023-06-15T11:47:56.784Z","metaMigratedFrom":"Content","title":"基礎動態規劃","breaks":true,"contributors":"[{\"id\":\"6b95215f-91a7-4eaf-bcfe-d43740108f96\",\"add\":3330,\"del\":247}]"}
    411 views
   owned this note