揹包吼哇!ide
基礎的揹包分爲OI01揹包,徹底揹包,多重揹包,二維揹包,分組揹包,樹形揹包,求方案數等..........優化
做爲DP的一個基礎部分仍是有必要寫一寫的。spa
01揹包:code
一個物品能取1次。
blog
設f[i][j]表示i物品j體積的最大權值,則狀態轉移方程:隊列
f[i][j] = max(f[i - 1][j], f[i - 1][j - c[i]] + v[i]);it
優化掉物品那一維:io
for i 1...nevent
for j V...c[i]
class
f[j] = max(f[j], f[j - c[i]] + v[i]);
徹底揹包:
物品能取任意屢次。
狀態同上。
for i 1...n
for j c[i]...V
f[j] = max(f[j], f[j - c[i]] + v[i]);
多重揹包:
一個物品可取若干次。
處理方法:
分組揹包:
物品被分紅若干組,每組只能選擇至多1個。
狀態:f[i][j]表示i組j體積的最大權值。
循環 + 狀態轉移方程:
for i 1...g
for j V...g[i].min_c
for k g[i].s...g[i].t
if(j >= c[k])
f[j] = max(f[j], f[j - c[k]] + v[k]);
二維揹包:
費用限制爲二維。
此時咱們只須要把狀態加一維便可解決。
for i 1...n
for jA VA...cA[i]
for jB VB...cB[i]
f[jA][jB] = max(f[jA][jB], f[jA - cA[i]][jB - cB[i]] + v[i]);
可行性徹底揹包:
能夠用bitset解決
樹形揹包:
本質是分組揹包。把子節點的不一樣體積看作組內不一樣物品。
例題:洛谷P2014 選課
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 310; 5 6 struct Edge { 7 int nex, v; 8 }edge[N]; int top; 9 10 int e[N], v[N], f[N][N], n, m, root; 11 12 inline void add(int x, int y) { 13 top++; 14 edge[top].v = y; 15 edge[top].nex = e[x]; 16 e[x] = top; 17 return; 18 } 19 20 void DFS(int x) { 21 for(int i = e[x]; i; i = edge[i].nex) { 22 int y = edge[i].v; 23 DFS(y); 24 // cal 25 for(int j = m; j >= 1; j--) { // 0 1 pack 26 for(int k = 0; k <= j; k++) { 27 f[x][j] = std::max(f[x][j], f[x][j - k] + f[y][k]); 28 } 29 } 30 } 31 if(x != root) { 32 for(int i = m; i >= 1; i--) { 33 f[x][i] = f[x][i - 1] + v[x]; 34 } 35 } 36 return; 37 } 38 39 int main() { 40 scanf("%d%d", &n, &m); 41 root = n + 1; 42 for(int i = 1, x; i <= n; i++) { 43 scanf("%d%d", &x, &v[i]); 44 add(x ? x : root, i); 45 } 46 DFS(root); 47 printf("%d", f[root][m]); 48 return 0; 49 }
注意要倒序循環V的理由是這是01揹包,一個物品只能取一次。