dp
dynamic programming
動態規劃
費式數列
\(f(x) = f(x - 1) + f(x - 2)\)
直接遞迴好像很慢
把算過的用陣列存起來
一些名詞
狀態
在某種情況下的解
dp[x]是費氏數列第x項
轉移
幾種不同狀態之間的關係
\(dp[x] = dp[x - 1] + dp[x - 2]\)
AtCoder DP Contest
對於一個可以走的格子,一定是從左邊或上面走過來的
定義\(dp[i][j]\)為走到\((i,j)\)的方法數
- 如果\((i, j)\)不能走,\(dp[i][j] = 0\)
 - 如果可以走,\(dp[i][j] = dp[i - 1][j] + dp[i][j - 1]\)
 
背包問題
直接把重量定成狀態
定義\(dp[i][j]\)代表目前有前i個物品,背包放到重量為j的最大價值
第i個物品的重量為\(w[i]\), 價值為\(v[i]\)
想一下怎麼轉移
一個物品可以分成要選或不選
一個物品可以分成要選或不選
一個物品可以分成要選或不選
不選
不會用到第i個物品
只會使用前i-1個來達到重量j
\(dp[i][j]=dp[i - 1][j]\)
一個物品可以分成要選或不選
不選
不會用到第i個物品
只會使用前i-1個來達到重量j
\(dp[i][j]=dp[i - 1][j]\)
選
要用到第i個物品
前i-1個總重量只能是\(j-w[i]\)
會拿到的價值是
\(dp[i - 1][j - w[i]] + v[i]\)
\(dp[i][j] = dp[i - 1][j - w[i]] + v[i]\)
一個物品可以分成要選或不選
不選
\(dp[i][j]=dp[i - 1][j]\)
選
\(dp[i][j] = dp[i - 1][j - w[i]] + v[i]\)
要選價值最高的
\(dp[i][j] = max(dp[i - 1][j], dp[i - 1][j-w[i]]+v[i])\)
時間複雜度
設背包最大重量為\(W\)
時間複雜度
設背包最大重量為\(W\)
有\(n\times W\)個狀態 => \(O(nW)\)
每個狀態的轉移分成要拿或不拿 => \(O(1)\)
時間複雜度
設背包最大重量為\(W\)
有\(n\times W\)個狀態 => \(O(nW)\)
每個狀態的轉移分成要拿或不拿 => \(O(1)\)
\(O(nW) \times O(1) = O(nW)\)
時間複雜度\(O(nW)\)
空間複雜度
\(O(nW)\)
優化
看\(i\)的時候只需要\(i - 1\)的狀態
所以只需要記\(i\)和\(i-1\)
空間複雜度\(O(W)\)
再優化
只記一個陣列,每次從上到下轉移
\(W\)很大,\(O(nW)\)會TLE
v很小
可以把v定成狀態
無限背包
\(dp[i][j] = max(dp[i - 1][j], dp[i][j-w[i]]+v[i])\)
每種物品都有無限多個
直接從i轉移
一樣可以做空間優化
直接從下到上轉移
有限背包
第i種物品有a[i]個
暴力作法:
每種物品都拆成a[i]個物品
做01背包
區間DP
把區間範圍定成狀態
dp[i][j]表示切一個從第i個切割點到第j個切割點之間的棍子的最小成本
(i跟j點是邊界,不能切)
把區間範圍定成狀態
dp[i][j]表示切一個從第i個切割點到第j個切割點之間的棍子的最小成本
(i跟j點是邊界,不能切)
選擇切割點
如果選擇k點當作切割點(\(i<k<j\))
則成本為\(a[j] - a[i]+dp[i][k]+dp[k][j]\)
原本棍子長度 剩餘的棍子切割成本
狀態壓縮DP
用dp狀態紀錄已經走過的點
可以用二進位的方式記錄走過的點的集合
dp[S][i]代表已走過S裡的所有點,且現在在i點
dp[S][i]代表已走過S裡的所有點,且現在在i點
所能得到的最短路徑
用dp狀態紀錄已經走過的點
可以用二進位的方式記錄走過的點的集合
dp[S][i]代表已走過S裡的所有點,且現在在i點
所能得到的最短路徑
舉例
\(n = 5, dp[01101][2]\)
走過{1, 2, 4}的點,且現在在2
dp[S][i]
轉移可以從S中選一個當作前一個點
選到的點要可以走到i
dp[i][S]:
前i個男生已經匹配,S集合內的女生也已經匹配
dp[i][S]:
前i個男生已經匹配,S集合內的女生也已經匹配
轉移
每次決定第i個男生要跟誰配對
dp[i][S]:
前i個男生已經匹配,S集合內的女生也已經匹配
轉移
每次決定第i個男生要跟誰配對
複雜度
\(O(n^2 2^n)\)
dp[i][S]:
前i個男生已經匹配,S集合內的女生也已經匹配
轉移
每次決定第i個男生要跟誰配對
複雜度
\(O(n^2 2^n)\)
可以更快嗎?
很顯然的
男生已經匹配數量 = 女生已經匹配數量
很顯然的
男生已經匹配數量 = 女生已經匹配數量
所以只需要數S裡面有多少個1
就可以知道i是多少
i就可以省略掉
複雜度
\(O(n2^n)\)
單調對列優化
給一個長度為n的序列a
請輸出對於\(1 \leq i \leq n\)
區間max(0, i - k)到i的最小值
如果有一個\(j < i且a[j] \geq a[i]\)
那j在之後都沒有用了
首先讓i從1跑到n
dp
By scottchou
dp
- 256