# 111 選手班 - 動態規劃
###### tags: `宜中資訊` `CP`
2022.08.16
[110 slides](https://hackmd.io/@Ccucumber12/Bk6lLyuxF#/)
[背包九講](http://www2.lssh.tp.edu.tw/~hlf/class-1/lang-c/DP.pdf)
## 簡介
Dynamic Programming 動態規劃
- 把大問題分成小問題
- 記錄小問題的答案避免重複計算
- 以空間換取時間
### 三步驟求DP
#### 狀態
- 可以怎麼拆解問題?
- 有哪些資訊是必要的?
- 可以從狀態中求出答案嗎?
- 狀態大小
#### 轉移
- 如何獲得狀態答案?
- 該用甚麼順序計算?
- 轉移耗時
#### 初始
- 有哪些已知的答案?
### 計算方式
#### Top Down
透過遞迴分割問題,並將答案記錄起來。
如果遞迴到計算過的狀態,則直接回傳。
類似DFS
- 直覺簡單
- 不須煩惱計算順序
- 效率差 可能stack overflow
#### Bottom Up
透過迴圈,從初始狀態開始,將所有答案計算出來
- 效率高
- 常見(?
- 可能計算非必要狀態
- 反直覺 需考慮順序
## 基礎問題
### 合併史萊姆
有 $N$ 個史萊姆,第 $i$ 個大小為 $a_i$。
每次可以花費 $a_i + a_{i+1}$ 合併兩個相鄰的史萊姆,之後他們會合併成一個大小為兩個之和的史萊姆。
請問最小要花費多少才能將所有史萊姆合併成為一個。
- 狀態:$f(l, r) =$ 將 $l$ 到 $r$ 合併為一個史萊姆的花費
- 轉移:
- 切在 $l$:$f(l, l) + f(l+1, r)$
- 切在 $l+1$:$f(l, l+1) + f(l+2, r)$
- ...
- $f(l, r) = \displaystyle\min_{l \le i \le r} \{f(l, i) + f(i+1, r)\}$
時間複雜度
- 狀態:$\mathcal O(N^2)$
- 轉移:$\mathcal O(N)$
- 總計:$\mathcal O(N^3)$
### LCS
Longest Common Subsequence 最長共同子序列
給定兩個字串 $s, t$,請找到一個最長的字串使的它是 $s$ 和 $t$ 的共同子序列。
- 狀態:$f(i, j) =$ $s[1,i]$ 和 $t[1,j]$ 的 LCS
- 轉移
- $s[i] = t[j]$:$f(i-1, j-1) + 1$
- 不選:$\max\{f(i-1, j), f(i, j-1)\}$
時間複雜度
- 狀態:$O(N^2)$
- 轉移:$O(1)$
- 總計:$O(N^2)$
### LIS
Longest Increasing Subsequence 最長遞增子序列
給定一個序列,請找到一個最長的子序列使得它是遞增的
- 狀態:$f(i) =$ 選 $a[i]$ 下,$a[1,i]$ 的LIS
- 轉移:
- 限制:前一個選的數字要 $\le a[i]$
- $dp[i] = \displaystyle\max_{j<i \& a[j] < a[i]}(dp[j]) + 1$
時間複雜度
- 狀態:$\mathcal O(N)$
- 轉移:$\mathcal O(N)$
- 總計:$\mathcal O(N^2)$
#### 二分搜優化
- 若 $a[i] \le a[j]$ 且 $dp[i] \ge dp[j]$ 則 $a[j]$ 永遠不會被選到
- 紀錄所有可能會用到的 $(a[i], dp[i])$
- $dp[i]$ 恰巧會是每格 $+1$
- 只記錄 $(a[i])$
- 此時紀錄的 $a[i]$ 會是嚴格遞增
- 二分搜!
時間複雜度
- 狀態:$\mathcal O(N)$
- 轉移:$\mathcal O(\log N)$
- 總計:$\mathcal O(N\log N)$
#### 用 LIS 做 LCS
記錄每個字元在其中一個字串的位置,並尋找另外一個字串的LIS
## 背包問題
### 01 背包 價值好高
[例題一](https://atcoder.jp/contests/dp/tasks/dp_d)
- 給定 $N$ 個物品,第 $i$ 個物品重量$w_i$,價值$v_i$
- 背包容量 $W$
- 選擇一些物品,使得重量總和不超過容量,請問最大價值總和為何?
- $N \leq 100$,$W \leq 10^5$
**每個物品**
- 0: 不選,重量$+0$,價值$+0$
- 1: 選擇,容量$-w_i$,價值$+v_i$
**DP**
- $\text{dp}[i][j]:=$只能選前 $i$ 個物品的情況下,背包容量為 $j$ 的最大價值總和。
- 考慮第 $i$ 個物品
- 0: $\text{dp}[i][j] = \text{dp}[i-1][j]$
- 1: $\text{dp}[i][j] = \text{dp}[i-1][j-w_i]+v_i$
- Ans: $\text{dp}[N][W]$
**時間複雜度**
- Time: $\mathcal{O}(NW)$
- Space: $\mathcal{O}(NW)$
### 01 背包 重量好大
[例題二](https://atcoder.jp/contests/dp/tasks/dp_e)
- 給定 $N$ 個物品,第 $i$ 個物品重量$w_i$,價值$v_i$
- 背包容量 $W$
- 選擇一些物品,使得重量總和不超過容量,請問最大價值總和為何?
- $N \leq 100,W \leq 10^9,\sum v_i \leq 10^5$
**DP**
- $\text{dp}[i][j]:=$只能選前 $i$ 個物品的情況下,價值總合為 $j$ 的最小重量總和。
- 考慮第 $i$ 個物品
- 0: $\text{dp}[i][j] = \text{dp}[i-1][j]$
- 1: $\text{dp}[i][j] = \text{dp}[i-1][j-v_i]+w_i$
**答案**
- 對於所有 $\text{dp}[i][j] \leq W$
- Max $j$
**初始化**
- $\text{dp}[i][0] = 0$
- $\text{dp}[i][j] = \inf, (j > 0)$
**時間複雜度**
- Time: $\mathcal{O}(N\sum v_i)$
- Space: $\mathcal{O}(N\sum v_i)$
### 無限背包
- 給定 $N$ 種物品,第 $i$ 種物品重量$w_i$,價值$v_i$
- 背包容量 $W$
- 選擇任意數量物品,每種不限個數,使得重量總和不超過容量,請問最大價值總和為何?
- $N \leq 100,W \leq 10^5$
**DP與轉移式**
- $\text{dp}[i][j]:=$只能選前 $i$ 個物品的情況下,背包容量為 $j$ 的最大價值總和。
- 考慮第 $i$ 個物品
- 0: $\text{dp}[i][j] = \text{dp}[i-1][j]$
- 1: $\text{dp}[i][j] = \text{dp}[i-1][j-w_i]+v_i$
- 2: $\text{dp}[i][j] = \text{dp}[i-1][j-2w_i]+2v_i$
- 3: $\text{dp}[i][j] = \text{dp}[i-1][j-3w_i]+3v_i$
- $\dots$
- 時間複雜度:$\mathcal O(NW)\times\mathcal O(W)$
**01與無限的差別**
- $\text{dp}[i][j] = \text{dp}[i-1][j - w_i] + v_i$
- 每項物品只能選一次
- 01背包
- $\text{dp}[i][j] = \text{dp}[i][j - w_i] + v_i$
- 每項物品選完之後還能選
- 無限背包
**優化**
- $\text{dp}[i][j]:=$只能選前 $i$ 個物品的情況下,背包容量為 $j$ 的最大價值總和。
- 考慮第 $i$ 個物品
- 0: $\text{dp}[i][j] = \text{dp}[i-1][j]$
- 1: $\text{dp}[i][j] = \text{dp}[i][j-w_i]+v_i$
- 複雜度
- 時間: $\mathcal{O}(NW)$
- 空間: $\mathcal{O}(NW)$
### 分組背包
- 給定 $N$ 個物品,第 $i$ 個物品重量$w_i$,價值$v_i$,屬於組別 $k_i$
- 背包容量 $W$,物品共分為 $K$ 組
- 每組最多選擇一件物品,使得重量總和不超過容量,請問最大價值總和為何?
- $N,K \leq 100$,$W \leq 10^5$
**DP**
- $\text{dp}[i][j]:=$只能選前 $i$ **組**物品的情況下,背包容量為 $j$ 的最大價值總和。
- 考慮第 $i$ **組**物品
- 考慮第 $i$ 組物品內,第 $u$ 個物品
- 0: $\text{dp}[i][j] = \text{dp}[i-1][j]$
- 1: $\text{dp}[i][j] = \text{dp}[i-1][j-w_u]+v_u$
- Ans: $\text{dp}[K][W]$
**複雜度**
時間: $\mathcal{O}(NW)$
空間: $\mathcal{O}(NW)$
## 題單
- [Contest](https://vjudge.net/contest/510748#overview)
- Password: `111apcs`