简单dp 学习笔记
1. 背包
1.1 背包模型的概述
有
1.2 0/1背包
考虑每种物品只有一个的情况。
我们设
于是得出 dp 方程:
我们发现,
for(int i=1; i<=n; i++) for(int j=V; j>=w[i]; j--) f[j]=max(f[j],f[j-w[i]]+v[i]);
1.3 完全背包问题
即每种物品有无数个。
考虑同样的 dp 转移,只是将倒序枚举改为正序,这样就变成选无限个了。
for(int i=1; i<=n; i++) for(int j=w[i]; j>=V; j++) f[j]=max(f[j],f[j-w[i]]+v[i]);
1.4 多重背包问题
给出每种物品有
一个最简单的想法是直接把
考虑倍增,将物品拆成
int cnt=0; for(int i=1,v,w,s;i<=n;i++){ rd(w,v,s); for(int j=1; j<=s; j<<=1) w[++cnt]=j*w,v[cnt]=j*v,s-=j; if(s) w[++cnt]=s*w,v[cnt]=s*v; } for(int i=1; i<=cnt; i++) for(int j=V; j>=w[i]; j--) f[j]=max(f[j],f[j-w[i]]+v[i]);
1.5 “恰好为 V”
问能否从中选取若干件总价值恰好为
转移同理。
1.6 有依赖的背包
考虑依赖关系,对子集进行讨论,枚举子树哪些被选。
1.7 背包的方案计数
考虑如果不需要最优解,直接将取 max 改为求和即可。
否则记
2. 区间 dp
区间 dp 经典方程式:
断环为链,直接做。
3. 树形 dp
3.1 simple
设
于是可以知道
dfs 转移。
3.2 树上背包
建图,发现是一个森林。
我们设
转移的过程结合了树形 DP 和 背包 的特点,我们枚举
记点
注意上面状态转移方程中的几个限制条件,这些限制条件确保了一些无意义的状态不会被访问到。
可以证明,该做法的时间复杂度为
3.3 换根 dp
换根 dp 通过预处理换根的贡献,使得仅用两次 dfs 可以处理一些问题。
通常在出现在无根树或者需要对每个点计算答案时考虑换根。
不妨令
考虑计
考虑让根从 u 换到 v,这样 v 的子树中的点的 dep--, v 字数外的点的 dep++,可以知道
直接转移即可。
4.DAG 上 dp
考虑拓扑排序,从入度为 0 的点开始记忆化搜索,这样可以方便的计算答案。
5.状压 dp
5.1 朴素的状压 dp
如果遇到
考虑 P2704,记录当前有炮兵的位置,在计数时对其他的地方加上贡献即可。
5.2 一些常用的优化技巧:
两边 dp(与 meet in middle 同理)、阈值分治。
5.3 子集 dp
有时候需要枚举一个数的子集来转移给这个数。
但是如何快速的枚举子集的子集?
考虑这样一个东西:
int full=1<<n; for(int s=0; s<full; s++) for(int s1=s; s1; s1=(s1-1)&s) ......
考虑这个 s1 的意义:依次消去 s 的每一位,故为枚举子集。
这个东西用二项式定理证出来是
本文作者:lgh_2009
本文链接:https://www.cnblogs.com/lgh-blog/p/18046725
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!