背包吼哇!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背包,一个物品只能取一次。