# DSA homework 5 演習課 ###### tags: `Course DSA` https://reurl.cc/y4yz2 --- ## 目錄 --- * Top down VS Bottom up * 解決一個 DP 問題 ---- ## Top down VS Bottom up 以計算組合數 $C_{m}^{n}$ 為例: * 計算 $0 \le m \le n \le 1000$ 的所有 $C_{m}^n \% 10^9+7$ * Pascal's rule * $\displaystyle C_{m}^{n} = C_{m}^{n - 1} + C_{m - 1}^{n - 1}$ ---- ## 名詞定義 * 狀態:以 $(n, m)$ 兩個數字表示 $C_{m}^{n}$ * 轉移:狀態和狀態之間的關係 * $C_{m}^{n} = C_{m}^{n - 1} + C_{m - 1}^{n - 1}$ * DP 複雜度: * $O(狀態複雜度 \times 轉移複雜度)$ * $有多少東西要算 \times 算一個要多久$ --- ## Bottom up * 多以迴圈實作 * 由較小的子問題算出較大的子問題 * 特性:程式碼簡潔、比較不直觀 ---- ## Bottom up - code ``` cpp int c[max][max], mod = 1000000007; for(int n = 0; n <= 1000; n ++){ for(int m = 0; m <= n; m ++){ if(n == m || m == 0) c[n][m] = 1; else c[n][m] = (c[n - 1][m] + c[n - 1][m - 1]) % mod; } } ``` --- ## Top down * 以遞迴計算子問題的答案 * 由較大的子問題遞迴算出較小的子問題 * 記憶化搜索:每個子問題只計算一次 * 特性:接近思考方式、實作直觀 ---- ## Top down - code ``` cpp int c[max][max], solved[max][max]; // init solved false int C(int n, int m){ if(solved[n][m] == true) return c[n][m]; solved[n][m] = true; if(n == m || m == 0) return c[n][m] = 1; else return c[n][m] = (C(n - 1, m) + C(n - 1, m - 1)) % mod; } ``` ---- ## 記憶化搜索 or not * 有記憶化搜索: * 每個狀態 $C(n, m)$ 只會被計算一次 * 總複雜度:$O(n^2)$ * 沒有有記憶化搜索: * 算 $C(n, m)$ 時間複雜度為 $O(C^n_{m})$ * 總複雜度:$O(2^n)$ --- ## 解決一個 DP 問題 1. 找有同樣結構的子問題 2. 訂定狀態 & 狀態轉移 3. 計算複雜度 4. AC? --- ## 找有同樣結構的子問題 * 一個 $N \times M$的方格紙可做的操作: * 撕掉一行 * 撕掉一列 * 變成比較小張的方格紙片,發現方格紙片: * 是原本方格紙的連續區域 * 適用相同的規則(子問題) --- ## 訂定狀態 & 狀態轉移 * 目前子問題: 一張方格紙片的答案 (方法數) * 目前的狀態: $(L_1, R_1, L_2, R_2)$ * 目的:表達方格紙片的資訊 * $L_1, R_1$:在原先方格紙上的 $[L_1, R_1]$ 行 * $L_2, R_2$:在原先方格紙上的 $[L_2, R_2]$ 列 * 整張紙就是 $(1, M, 1, N)$ * 這樣可以轉移了嗎 ---- ![](https://i.imgur.com/TVaEPK0.png) ---- ![](https://i.imgur.com/zOj7YSv.png) ---- 紙片$(L_1, R_1, L_2, R_2)$ -> * A紙片:$(L_1, X - 1, L_2, R_2)$ * B紙片:$(X + 1, R_1, L_2, R_2)$ * 讓 $V_A=Ans(A紙片), V_B=Ans(B紙片)$ 可以合併答案嗎 * $V_A \times V_B?$ No, 可以交互撕 --- 不能合併答案,A、B兩張紙片可能會產生交互影響 ---- 增加會撕掉幾個步驟,紙片總共撕 K 次 增加狀態的維度: 從 $(L_1, R_1, L_2, R_2)$ 變 $(L_1, R_1, L_2, R_2, K)$ ---- 紙片$(L_1, R_1, L_2, R_2, K)$ -> * A紙片:$(L_1, X - 1, L_2, R_2, K_A)$ * B紙片:$(X + 1, R_1, L_2, R_2, K - 1 - K_A)$ 其中 $0 <= K_A <= K - 1$ ---- ### 可以轉移 --- 紙片$(L_1, R_1, L_2, R_2, K)$ -> * $V_A = Ans(L_1, X - 1, L_2, R_2, K_A)$ * $V_B = Ans(X + 1, R_1, L_2, R_2, K - 1 - K_A)$ 則選擇第 $X$ 行撕下去後,剩下的的 $K - 1$ 次會有 $\displaystyle C^{K - 1}_{K_A} \times V_A \times V_B$ 種撕的方法 --- ## 總結 --- 執行 $K$ 次的方法 $=\sum_{所有可能的一次}$ 執行 $K - 1$ 次的方法 ---- ## 總結 --- $Ans(L_1, R_1, L_2, R_2, K)=\sum_X\sum_{K_A} C^{K - 1}_{K_A} \times$ $Ans(紙片A,K_A) \times Ans(紙片B,K - 1 - K_A)$ * 其中 $X$ 為滿足條件的撕法(包含行、列) Final Ans: $\sum_K Ans(1, M, 1, N, K)$ ---- ## 注意事項 ? --- * $(L_1, R_1, L_2, R_2, K)$遞迴要到甚麼時候停下來 * $K = 0$ * 已經不能撕了 * 讓數值保持在 $[0, 10^9+7)$ * 計算過程 long long --- ## 複雜度分析 * 統一以 $N$ 表示: * 狀態複雜度:$(L_1, R_1, L_2, R_2, K)$ * 數量級$(N, N, N, N, N^2) = O(N^6)$ * $K$ 的量級: $O(N^2)$ * 轉移複雜度:枚舉$(X, K_A)$ * 數量級$(N, N^2) = O(N^3)$ * $0 <= K_A <= K - 1$ * 整體複雜度: $O(N^9)$ * 本題常數很小
{"metaMigratedAt":"2023-06-14T21:48:32.058Z","metaMigratedFrom":"Content","title":"DSA homework 5 演習課","breaks":true,"contributors":"[{\"id\":\"9ecbc46a-6286-429a-9253-019ea930a55b\",\"add\":4459,\"del\":1241}]"}
    1073 views