分类
-
01背包
-
完全背包
-
多重背包
一、01背包
解决问题:n个物品有价值和重量两个属性,容量为m的背包,每个物品只取一次,能取到的最大价值
状态定义:dp[i][j]表示在前i个物品中选,容量为j,能取到的最大价值
状态转移:dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+c[i])这个物品取或者不取两种情况
滚动数组优化:第一维只与i-1有关,倒序转移
复杂度是(O(nm))的
例题:HDU Bone Collector luogu 采药 0629模拟赛T1也可以算01背包吧……
其实还是想找一些高质量的例题吧,这些都太裸了,有时间再看看
完全背包
解决问题:n个物品有价值和重量两个属性,容量为m的背包,每个物品可以取无数次,能取到的最大价值
状态定义:dp[i][j]表示在前i个物品中选,容量为j,能取到的最大价值
状态转移:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+c[i]) 选或者不选
滚动数组优化:需要覆盖,正序枚举
复杂度是(O(nm))的
例题:luogu 疯狂的采药
多重背包
解决问题:n个物品有价值和重量两个属性,容量为m的背包,每个物品可以取有限次,能取到的最大价值
二进制转化:因为一个数可以被拆分成多个2的k次幂相加,把一个物品拆成2的k次幂个物品,每个物品只能选一次,变成了01背包
复杂度是(O(msumlimits_{i = 1}^n logk_i))
代码:
void change(int tmpw,int tmpc,int tmpk){
for (int i = 1;i <= tmpk;i <<= 1){
w[++cnt] = i*tmpw,c[cnt] = i*tmpc;
tmpk -= i;
}
if (tmpk) w[++cnt] = tmpw*tmpk,c[cnt] = tmpc*tmpk;
}
例题:luogu 樱花
其他背包
一、恰好装满
将dp[0,...,N][0]初始为0,其它dp值均初始化为-inf
二、求方案总数
将取max/min 换成求和,例如:
dp[i][j] += dp[i-1][j]+dp[i-1][j-w[i]]+c[i]
三、二维费用背包
多开一维,其他和一维一样,比如01背包
dp[i][j] = max(dp[i-w1[k]][j-w2[k]],dp[i][j])
四、求最优方案
在转移的时候记录方案