背包
母题1:01背包
考虑
母题2:完全背包(from 1)
状态同上,转移本来应该为
可以用有限背包计数问题的思想:加入一个数,对所有数+1两类。
母题3:多重背包(from 1),理解方式
转移应该为
可以直接暴力,也有两种优化:
- 二进制优化,很好理解,对于一个物品若可选
个,可以拆成两个物品 倍和 倍,然后做01
背包,带一只 。 - 单调队列优化,不好理解,就是对于
同一个余数的情况一起处理,发现对于每种物品就是长度为 的定长滑动窗口求最值模型。P1776
母题4:分组背包(from 1)
就是某些物品在一个组内,组内只能选其一。
转移可以用
母题5:有依赖的背包问题(树上背包 的情况)/树上背包(from 4),重要!
acwing:https://www.acwing.com/activity/content/problem/content/1281/
y总写法:https://www.acwing.com/activity/content/code/content/118840/
不推荐y总写法,直接在输入时读入更方便,代码如下:
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int n, m;
int v[N], w;
int h[N], e[N], ne[N], idx;
int f[N][N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u)
{
for (int i = h[u]; ~i; i = ne[i]) // 循环物品组
{
int son = e[i];
dfs(e[i]);
// 分组背包
for (int j = m; j >= 0; j -- ) // 循环体积
for (int k = 1; k <= j - v[u]; k ++ ) // 循环决策
f[u][j] = max(f[u][j], f[u][j - k] + f[son][k]);
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
int root;
for (int i = 1; i <= n; i ++ )
{
int p;
cin >> v[i] >> w >> p;
f[i][v[i]]=w;// 将物品u加进去
if (p == -1) root = i;
else add(p, i);
}
add(0,root);
dfs(0);
cout << f[0][m] << endl;
return 0;
}
/*
加入0->root的解释:
假如只有一个点,如果在输入时插入,且 V>v1,又因为dfs不执行了,就会输出0,所以还是要把0作为根(如果按照y总写法最后加入就不需要)。(同样有多个点时也可能出现这种情况)或者说最后取一遍max。
*/
优化
可以参考 blog :
- https://www.cnblogs.com/ouuan/p/BackpackOnTree.html(严谨证明以后(希望有以后)再看)
- https://blog.csdn.net/m0_73386348/article/details/131838916(这篇博客分析有误,但是总结树形DP的分类是不二之选)
- https://www.cnblogs.com/purplevine/p/16751390.html(已经联系博主深刻理解了,先看这篇博客,一下分析基于此)
还有一篇博客:https://www.cnblogs.com/maple276/p/18005291,简单情况:https://www.cnblogs.com/maple276/p/12870572.html
解释一下正确性:
由于是 01
背包且
注意到树上背包有两种写法,一种直接输入到 dfs
函数中最后加入(需要偏移),为了与网上的博客保持一致防止错误,全部写成第一种。
注意一下复杂度分析讨论的都是“选课”一题的情况,
注意链接中的代码
只加上界优化不能保证复杂度是
1.的上下界优化:https://www.luogu.com.cn/record/173156416
1.的仅上界优化:https://www.acwing.com/problem/content/submission/code_detail/36537651/
2.的仅上界优化:https://www.acwing.com/problem/content/submission/code_detail/36537651/
2.的上下界优化:https://www.acwing.com/problem/content/submission/code_detail/36533419/
注意两道题枚举时要写成 j<=k-v
,因为必须保证当前必选。其中
容易发现,1. 是 2. 的特殊情况而已。
注意到 2. 最后需要取 max
(这里取
两道题都需要尽量输入的时候就处理到物品的体积和价值到对应的
// O(n^3)
for(int k = siz[u] + siz[v]; k >= 0; k--){
dp[u][k] = inf;
for(int j = 1; j <= siz[v] && j <= k; j++){//本题中应是j<=k-当前的v
dp[u][k] = min(dp[u][k], dp[u][k - j] + dp[v][j]);
}
}
siz[u] += siz[v];
// O(n^2)
for(int k = siz[u] + siz[v]; k >= 0; k--){
dp[u][k] = inf;
for(int j = max(k - siz[u], 1); j <= min(siz[v], k); j++){//同上
dp[u][k] = min(dp[u][k], dp[u][k - j] + dp[v][j]);
}
}
siz[u] += siz[v];
实测:上界优化效果可能比下界更好。
优化的复杂度分析
先别管树和抽象的倒序(倒序仅仅是01背包的需要),就只考虑两个背包:假设我们要把背包 lca
就是现在考虑到的点。如果不加下界优化,当
类似的证明:https://www.cnblogs.com/maple276/p/12870572.html 的开头部分
母题6:退背包(少见,就见过两道题)
https://www.cnblogs.com/wscqwq/p/17725571.html
根据物品插入无顺序,所以可以将要删去的数当作刚刚插入,就可以正着删除(因为是倒着插入)。
以上就是6个模型,接下来用x.表示母题x的变式
6
类背包,表示状态类似于,体积变为余数,考虑
8
本质还是背包,分类讨论,状态是由差值表示。1.
[26]
利用背包求解博弈论,体积变为余数。需要知道基本的必胜态、必败态。
[-20]
1.+矩阵快速幂。
[ABC287F] Components
5.+使用刷表法更简单,求连通块是多少的答案(这一维是背包)、树形考虑当前节点选不选丢入状态。
飞扬的小鸟
母题1,2的结合。主要2.
体积=高度。
大部分转移是2.,一个是1.,所以2.得用临时数组存储,再和1.取优。
碰顶特判。
AcWing 1155. Emiya 家今天的饭
背包问题拆解成前后两个部分,第一部分类似于01背包(用来满足前两个性质),可以使用前缀和优化;第三个性质难以满足,故再次DP把主导菜与其他菜差加入状态。第二部分还是01背包,维护差值。
AcWing 233. 换教室
最短路需要考虑相邻的情况,所以状态里加上一维。
通过期望的性质拆解贡献,配合最短路。1.
[ABC320F] Fuel Round Trip
有点像背包,但是考虑到对称点的限制,我们需要新立状态,按照一对一对的点,而不是前多少个点。1.
粉刷匠
首先是一个经典的线性DP的预处理,然后做一遍分组背包。4.
AcWing 487. 金明的预算方案
暴力枚举所有情况,拆物品(与5.思想不同,5.是拆分体积)分组背包即可。4.
有限背包计数问题
与根号分治结合,后半部分2.有划分数的思想:只有加入一个数,对所有数+1两类。
3.(统计数量所以用类前缀和)+2.
货币系统
需要证明找的
先排序,用小的组合出大的(因为小的不能用大的组合),就是给定一些物品,问凑出的个数,考虑2.,改变一下属性为 bool
。
每次遇到一个物品就看它能不能被凑出(能凑出就没必要存在了)。
A 马
考虑最后一匹马,活动只有三种,因此直接把活动设计到状态中。
总结
背包问题一般比较难的都是1.(可以和各种其他母题结合)(7很明显是完全背包,而且转移就是基本的转移,比母题还简单)。
转移有时需要分类讨论。
多种背包可能同时出现,一个背包问题可能可以拆解成好几个部分,两个部分有可能都是DP,也可能有一个是其他算法。
还可以出现与树形DP等结合使用。
多重背包类型的题目用单调队列(最优)或(类)前缀和(计数)。
分组背包拆分物品可以按照体积或者组合种类。
解法
- 写出转移式,确定种类。(多种见hint)
- 什么数值作为前
个物品,挖掘什么数值作为体积。
可以明确的按照前几个物品算出答案,并且可以从题目中挖掘出体积。
题目中出现的数值可以成为“体积”。
如果类似于斐波那契数列这样的转移,可以使用矩阵快速幂优化。
hint:如果1.+2.等多种背包在一个状态里转移(通过step1.判断),组合往往需要临时数组辅助分出两类转移。(题目分成两部分两次背包不属于此范畴)。
题目如果有多种约束,可以分类(如AcWing 1155. Emiya 家今天的饭,前两个好满足一类,第三个不好满足一类),利用容斥原理或其他技巧。
背包+求期望利用线性性拆解。
状态里可能有当前位置
状态的设计需要考虑求解的需求(如最短路对于最后一个位置选不选的要求)。
对称结构可以按照对称的一对来定义前
定义
描述: 有
解析:
根据定义可知,背包问题 V3 不属于背包问题。
本文作者:wscqwq
本文链接:https://www.cnblogs.com/wscqwq/p/17668706.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步