# Dynamic Programming > account: lyp > password: Apcs510562 ### APCSC #dp04 https://judge.apcs.camp/problems/31 ``` dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + value[i][j] ``` ### APCSC #dp05 https://judge.apcs.camp/problems/32 ``` dp[i][j] = 從(0,0)走到(i,j)的方法數 if (isObstacle(i,j)) { dp[i][j] = 0; } else { // the range of integer: - 2^31 ~ 2^31 - 1, -2*10^9 ~ 2*10^9 dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % 1000000007; } ``` | Column 1 | Column 2 | Column 3 | | -------- | -------- | -------- | | 1 | 1 | 1 | | 1 | 2 | 3 | | 1 | 3 | 6 | #### 式子裡有減號(1) ``` dp[i][j] = (dp[i-1][j] - dp[i][j-1] + 1000000007) % 1000000007; -2 % 5 = 3 (-2 + 5) % 5 = 3 ``` #### 式子裡有減號(2) ``` dp[i][j] = ((dp[i-1][j] - 100*dp[i][j-1]) % 1000000007 + 1000000007) % 1000000007 -2000 % 7 = -5 (-5 + 7) % 7 = 2 ``` ### APCSC #dp42 https://judge.apcs.camp/problems/66 ``` 0 -> green 1 -> blue 2 -> red dp[i][0] = 前i個數字都已經塗色,且第i個為綠色,的最大值 dp[i][1] = 前i個數字都已經塗色,且第i個為藍色,的最大值 dp[i][2] = 前i個數字都已經塗色,且第i個為紅色,的最大值 dp[i+1][0] = max(dp[i][1], dp[i][2]) + value[i+1]; dp[i+1][1] = max(dp[i][0], dp[i][2]); dp[i+1][2] = max(dp[i][0], dp[i][1]) - value[i+1]; answer = max(dp[N-1][0], dp[N-1][1], dp[N-1][2]); ``` ### APCSC #dp34 https://judge.apcs.camp/problems/60 ``` dp[i][0] = 第i個字母以前,出現幾個單獨的q dp[i][1] = 第i個字母以前,出現幾個qw dp[i][2] = 第i個字母以前,出現幾個qwq if (str[i] == 'q') { dp[i][0] = dp[i-1][0] + 1; dp[i][1] = dp[i-1][1]; dp[i][2] = dp[i-1][2] + dp[i-1][1]; } else if(str[i] == 'w') { dp[i][0] = dp[i-1][0]; dp[i][1] = dp[i-1][1] + dp[i-1][0]; dp[i][2] = dp[i-2][2]; } else { dp[i][0] = dp[i-1][0]; dp[i][1] = dp[i-1][1]; dp[i][2] = dp[i-1][2]; } // here dp[i][0] = 第i個字母以前,出現幾個單獨的q dp[i][1] = 第i個字母以前,出現幾個qw dp[i][2] = 第i個字母以前,出現幾個qwq if (str[i] == 'q') { dp[i][0] = dp[i-1][0]+1; } else { dp[i][0] = dp[i-1][0]; } if (str[i] == 'w') { dp[i][1] = dp[i-1][1]+dp[i-1][0]; } else { dp[i][1] = dp[i-1][1]; } if (str[i] == 'r') { dp[i][2] = dp[i-1][2]+dp[i-1][1]; } else { dp[i][2] = dp[i-1][2]; } answer = dp[N-1][2] ``` ### APCSC #dp13 區間dp N個沙堡,每次合併可以合併相鄰兩個,合併後順序不變,但合併的時候要付出x+y塊錢,x和y是被合併的兩個沙堡的重量。你的最終目標是要把所有的沙堡合併成為一個大沙堡,請問最少要花多少錢? ``` exampe: [1, 2, 3, 4] -> [3, 3, 4] -> [6, 4] -> [10] 3 + 6 + 10 [......] -> [...] + [...] -> final [a_1, a_2, ..., a_n] -> [a_1, ..., a_i] + [a_(i+1), ...a_n] dp[L][R]: 把第L個到第R個沙堡全部合併起來的成本。 dp[1][N]: 答案在這裡 dp[L][R] = min(dp[L][M] + dp[M+1][R] + sum(input[L~R])) = min(dp[L][M] + dp[M+1][R]) + sum(input[L~R]) , for all M in [L, R-1] // initialize others with INF for (int i = 0; i <= N; i++) dp[i][i] = 0; for (int i = 0 ; i < N ; i++){ int cnt = 0; while(cnt < N-1-i){ cnt++; int L = cnt, R = i + cnt + 1; for(int M = cnt ; M <= i+cnt+1 ; M++){ dp[L][R] = min(dp[L][R], dp[L][M] + dp[M+1][R]) + sum(input[L:R]); } } } // a clearer version for (int length = 1; length <= N-1; length++) { for (int L = 1; L <= N - length; L ++) { // calculate dp[L][L+length] int R = L + length; for (int M = L; M < R; M++) { dp[L][R] = min(dp[L][R], dp[L][M] + dp[M+1][R] + sum(input[L~R])); } } } ``` ![](https://i.imgur.com/okNMrRn.png) https://judge.apcs.camp/problems/40 ### APCSC #dp15 https://judge.apcs.camp/problems/42 ### Longest Common Subsequence ``` example: s_1 = "aabbcc", s_2 = "aabbbc" LCS = "aabbc" ``` ### Edit distance ``` s_1 = "aabbcc", s_2 = "aabbbc" * insert * replace * remove dp[i][j]: s_1[1~i] 要變成 s_2[1~j] if (s1[i] == s2[j]) { dp[i][j] = dp[i-1][j-1]; } else { (1) replace dp[i][j] = dp[i-1][j-1] + 1; (2) insert dp[i][j] = dp[i][j-1] + 1; (3) remove dp[i][j] = dp[i-1][j] + 1; } ``` ### 矩陣乘法問題 ``` A: (x, y) B: (y, z) A*B: (x, z) 兩個矩陣相乘,需要幾個步驟。 A*B所需要的乘法次數:x*y*z。 A*B*C*D*E = (A*B)*(C)*(D*E) A*B*C = (A*B)*C = A*(B*C) A: (w, x), B: (x, y), C: (y, z) w*x*y + w*y*z v.s. x*y*z + w*x*z (w*y)*(x+z) v.s. (x*z)*(x+w) A*B*C*D*E = A*(B*C*D*E) = (A*B)*(C*D*E) = ... = ... dp[1][n] = max(dp[1][1]+dp[2][n]+cost(), dp[1][2]+dp[3][n], ...) dp[l][r] = max(dp[l][k] + dp[k+1][r] + height(l)*width(k)*width(r)); = max(dp[l][k] + dp[k+1][r] + height(l)*height(k+1)*width(r)); ``` 照片: (1920, 1080) -> (1, 1920*1080) input: (1, 3) 1-st hidden layer: (1, 3) * (3, 4) = (1, 4) input: (1, 1920*1080) 1-st hidden layer: (1, 1920*1080) * (1920*1080, 20000) = (1, 20000) ### 2D區間和 ``` 1-D prefix sum: [1, 2, 3, 4, 5] -> [1, 3, 5, 10, 15] 2-D prefix sum: [1, 2, 3, 4] [9, 5, 6, 2] [5, 5, 5, 5] [ 1, 3, 6, 10] [10, 17, 26, 32] [.......] dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + a[i][j] (左上角是(1,1)、右下角是(i,j)的matrix總和) 那怎麼算左上角是(x1, y1)、右下角是(x2, y2)的matrix總和? dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1] 用O(N*M)的時間預處理,然後每次查詢子矩陣的總和都是O(1)。 ``` ### 面積最大方陣 ``` [0, 1, 1, 1] [1, 1, 1, 0] [0, 1, 1, 0] [1, 1, 1, 0] Answer: 2*2 = 4 dp[i][j]: 以(i,j)為右下角的最大方陣的邊長 dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 (if a[i][j] == 1) Where is our answer? max(dp[i][j]), for all i, j ``` ### Blocks https://onlinejudge.org/index.php?option=onlinejudge&Itemid=8&page=show_problem&problem=1500 ``` 任何一個sequence,最後消掉的顏色一定可以是最左邊或最右邊的顏色,反正是左邊是右邊都沒差,那我們就假設是右邊。 input: [0, 1, 1, 1, 1, 2, 2, 2, 0] -> [(0, 1), (1, 4), (2, 3), (0, 1)] 答案在這格: dp[1][4] = max(dp[1][3] + 1^2, dp[2][3] + 2^2) input: [0, 1, 0, 1, 0] dp[1][5] = max(dp[2][4] + 2^2) Next week we will introduce: dp[L][R][t] ``` ### Trapping Rain Water https://leetcode.com/problems/trapping-rain-water/ ### Best Time to Buy and Sell Stock https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ ``` i: i-th day k: k-th transaction dp[k][i] = the maximum profit after finishing the k-th transaction before the i-th day dp[k][i] = max(dp[k][i-1], dp[k-1][i-t] + price[i] - price[i-t]); If we enumerate all the possible t, the time complexity is O(K*N*N). In this case, K = 2. So O(N*N); Let j = i-t, 0 <= j < i. dp[k][i] = max(dp[k][i-1], max(dp[k-1][j] + price[i] - price[j]) ); Look closer at max(dp[k-1][j] + price[i] - price[j]) = max(dp[k-1][j] - price[j]) + price[i] Let profitMinusPrice[k][j] = dp[k][j] - price[j]. max(dp[k-1][j] + price[i] - price[j]) = max(dp[k-1][j] - price[j]) + price[i] = max(profitMinusPrice[k-1][j]) + price[i] -> O(1) To calculate dp[k][i], O(1). The time complexity of the whole task is O(k*N). ```