DP 复习
背包
约定使用 \(v_i\) 表示放入第 \(i\) 件物品的花费,\(w_i\) 表示第 \(i\) 件物品的价值,背包容量 \(M\),物品件数 \(N\)。
01 背包
每种物品仅有一件,可以选择放或不放。
设 \(f(i,j)\) 表示前 \(i\) 件物品恰填满容量为 \(j\) 的背包可以获得的最大价值。则其状态转移方程便是:
\]
若放第 \(i\) 件物品,那么问题就转化为“前 \(i-1\) 件物品放入剩下的容量为 \(j-v_i\) 的背包中”,此时能获得的最大价值就是 \(f(i-1,j-v_i)\) 再加上通过放入第 \(i\) 件物品获得的价值 \(w_i\);
如果不放第 \(i\) 件物品,那么问题就转化为“前 \(i - 1\) 件物品放入容量为 \(j\) 的背包中”,价值为 \(f(i-1,j)\)。
可以用滚动数组优化掉第一维,但注意要逆序枚举容量以达到“每种物品只能取一件”的限制。
for (int i = 1; i <= n; ++ i) {
for (int j = m; j >= v[i]; ++ j) {
f[j] = max(f[j], f[j - v[i]] + w[i];
}
}
若要求 恰好装满,则应将 \(f(1\ldots M)\) 初始化为 \(-\infty\),因为如果要求背包恰好装满,那么此时只有容量为 \(0\) 的背包可以在什么也不装且价值为 \(0\) 的情况下被“恰好装满”,反之,如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为 \(0\),所以初始时状态的值也就全部为 \(0\) 了。
完全背包
与 01 背包相似,但每种物品有无限件。
\]
可以用滚动数组优化掉第一维,但注意要 顺序 枚举容量以达到“每种物品可以取无限件”的限制。
完全背包的特点是每种物品可选无限件,所以在考虑“加选一件第 \(i\) 种物品”这种策略时,正需要一个可能已选入第 \(i\) 种物品的子结果 \(f(i, j − v_i)\),所以就可以并且必须采用 \(j\) 递增的顺序循环。
for (int i = 1; i <= n; ++ i) {
for (int j = v[i]; j <= m; ++ j) {
f[j] = max(f[j], f[j - v[i]] + w[i];
}
}
多重背包
与 01 背包相似,但每种物品最多取 \(k_i\) 件。
二进制拆分每个物品后跑 01 背包即可。
for (int i = 1; i <= n; ++ i)
{
cin >> a >> b >> m;
for (int j = 1; m - j >= 0; j <<= 1) //二进制拆分优化
{
++ cnt;
v[cnt] = a * j;
w[cnt] = b * j;
m -= j;
}
if (m)
{
++ cnt;
v[cnt] = a * m;
w[cnt] = b * m;
}
}
混合背包
有的物品只有一个,有的物品有无限个,还有的物品有有限个。
缝合怪,把前三种代码缝合起来即可。
二维费用背包
对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种费用。对于每种费用都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。
设第 \(i\) 件物品所需的两种费用分别为 \(c_i\) 和 \(v_i\)。两种费用可付出的最大值(也即两种背包容量)分别为 \(C\) 和 \(V\)。物品的价值为 \(w_i\)。
费用加了一维,只需状态也加一维即可。设 \(f(i,j,k)\) 表示前 \(i\) 件物品付出两种费用分别为 \(j\) 和 \(k\) 时可获得的最大价值。状态转移方程就是:
\]
仍然可以滚动数组,按照背包类型确定枚举顺序即可。
有时,“二维费用”的条件是以“最多只能取 U 件物品” 来给出的。这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为 1,可以付出的最大件数费用为 U。
另一种看待二维背包问题的思路是:将它看待成复整数域上的背包问题。也就是说,背包的容量以及每件物品的费用都是一个复整数。而常见的一维背包问题则是自然数域上的背包问题。所以说,一维背包的种种思想方法,往往可以应用于二位背包问题
的求解中,因为只是数域扩大了而已。
分组背包
有 \(N\) 件物品和一个容量为 \(V\) 的背包。第 \(i\) 件物品的费用是 \(v_i\),价值是 \(w_i\)。这些物品被划分为 \(K\) 组,每组最多选一件物品。
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。
设 \(f(i,j)\) 表示前 \(f\) 组物品花费费用 \(j\) 能取得的最大权值,则有:
\]
其中 \(k\) 是组 \(i\) 内的一件物品。
for (int i = 1; i <= K; ++ i)
for (int j = V; j >= 0; -- j)
for (int k : group[i])
// 遍历组 i 的每一件物品
if (j - v[k] >= 0)
f[j] = max(f[j], f[j - v[k]] + w[k];
有依赖的背包
其实是树形 DP。
咕咕咕。
泛化物品
在背包容量为 \(V\) 的背包问题中,泛化物品是一个定义域为 \(\{x\in\mathbf{Z} \mid 0\leq x\leq V\}\) 的函数 \(h\),当分配给它的费用为 \(v\) 时,能得到的价值就是 \(h(v)\)。
如果给定了两个泛化物品 \(h\) 和 \(l\),要用一定的费用从这两个泛化物品中得到最大的价值,这个问题怎么求呢?事实上,对于一个给定的费用 \(v\),只需枚举将这个费用如何分配给两个泛化物品就可以了。同样的,对于 \([0,V]\) 中的每一个整数 \(v\),可以求得费用\(v\) 分配到 \(h\) 和 \(l\) 中的最大价值 \(f(v)\)。也即
\]
可以看到,这里的 \(f\) 是一个由泛化物品 \(h\) 和 \(l\) 决定的定义域为 \(\{x\in\mathbf{Z} \mid 0\leq x\leq V\}\) 的函数,也就是说, \(f\) 是一个由泛化物品 \(h\) 和 \(l\) 决定的泛化物品。
本文所有代码均未经过编译。
大部分参考 崔天翼《背包九讲》。
Written with StackEdit.
DP 复习的更多相关文章
- 区间DP复习
区间DP复习 (难度排序:(A,B),(F,G,E,D,H,I,K),(C),(J,L)) 这是一个基本全在bzoj上的复习专题 没有什么可以说的,都是一些基本的dp思想 A [BZOJ1996] [ ...
- 集训DP复习整理
DP复习 集训%你赛2:测绘(审题DP) 经过2000+个小时的努力终于把这道题做出来的蒟蒻通 分析: 这道题我一直没做出来的原因就是因为我太蒟了题面看不懂,题面读懂了,其实不是特别难. 题目翻译: ...
- 状压DP复习
深感自己姿势水平之蒻……一直都不是很会状压DP,NOIP又特别喜欢考,就来复习一发…… 题目来源 Orz sqzmz T1 [BZOJ4197][NOI2015]寿司晚宴 (做过)质因数分解最大的质因 ...
- 状压DP复习笔记
前言 复习笔记第4篇.CSP RP++. 引用部分为总结性内容. 0--P1433 吃奶酪 题目链接 luogu 题意 房间里放着 \(n\) 块奶酪,要把它们都吃掉,问至少要跑多少距离?一开始在 \ ...
- 斜率优化DP复习笔记
前言 复习笔记2nd. Warning:鉴于摆渡车是普及组题目,本文的难度定位在普及+至省选-. 参照洛谷的题目难度评分(不过感觉部分有虚高,提高组建议全部掌握,普及组可以选择性阅读.) 引用部分(如 ...
- 矩阵乘法优化DP复习
前言 最近做毒瘤做多了--联赛难度的东西也该复习复习了. Warning:本文较长,难度分界线在"中场休息"部分,如果只想看普及难度的可以从第五部分直接到注意事项qwq 文中用(比 ...
- 数位DP复习笔记
前言 复习笔记第五篇.(由于某些原因(见下),放到了第六篇后面更新)CSP-S RP++. luogu 的难度评级完全不对,所以换了顺序,换了别的题目.有点乱,见谅.要骂就骂洛谷吧,原因在T2处 由于 ...
- NOIP 考前DP 复习
POJ 2533 最长不降子序列 #include <cstdio> ; int a[Maxn],Pos[Maxn],F[Maxn],n,Ans; inline int Max(int x ...
- 树形DP 复习
树形DP 树形DP:建立在树上的动态规划 一般有两种传递方式:根→叶或叶→根 前者出现在换根DP中,一般操作是求出某一个点的最优解,再通过这一个点推知其他点的最优解. 后者是树形DP的常见形式,一般树 ...
- 数位DP复习小结
转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8490222.html 之前学数位dp的时候底子没打扎实 虚的要死 这次正好有时间……刷了刷之前没做的题目 感觉自 ...
随机推荐
- Linux 上的 .NET 如何自主生成 Dump
一:背景 1. 讲故事 前几天微信上有位朋友找到我,说他程序的 线程数 会偶发性瞬时飙高,让我看下大概是什么原因,截图如下: 如果这种问题每天都会出现,比较好的做法就是用 dotnet-trace 捕 ...
- qrcode模块生成二维码
安装qrcode模块 pip install qrcode 简单使用 import qrcode data = 'hello world' img = qrcode.make(data) # 显示二维 ...
- BeanDefinitionStoreException: Failed to read candidate component class
ssm 整合时出现问题 org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate ...
- 基于GPT搭建私有知识库聊天机器人(五)函数调用
文章链接: 基于GPT搭建私有知识库聊天机器人(一)实现原理 基于GPT搭建私有知识库聊天机器人(二)环境安装 基于GPT搭建私有知识库聊天机器人(三)向量数据训练 基于GPT搭建私有知识库聊天机器人 ...
- hexo博客yilia主题_缺失模块_解决方案
hexo博客yilia主题,左侧栏目有一个全部文章的按钮,刚开始开始报错缺失模块,如下图: 我解决了这个问题着实不容易饶了弯路,但是跟着提示步骤,其实很简单,走起: 1.查看node版本 win键+R ...
- linux基础命令及常用命令总结
1.ls命令 ls命令是最基础的命令之一,作用是列出当前目录下所有的文件和目录.ls命令有很多选项可以使用,比较常用的是-l选项,可以以详细信息的形式列出所有文件和目录的信息. 示例:列出当前目录下的 ...
- 【Azure Event Hub】Event Hub的Process Data页面无法通过JSON格式预览数据
问题描述 在Event Hub的门户页面中,可以通过Process Data页面查看Event Hub中的数据,但是当使用JSON格式预览时(View in JSON),却出现错误. 消息一: No ...
- linux 内核的ksm机制
KSM(Kernel Samepage Merging),是Linux内核中的一种内存优化机制,它能够通过将多个应用程序中的相同内存页合并,实现虚拟内存的节约.KSM通过比较不同进程间的虚拟内存页,如 ...
- 文心一言 VS 讯飞星火 VS chatgpt (66)-- 算法导论6.5 5题
五.试分析在使用下列循环不变量时,HEAP-INCREASE-KEY 的正确性:在算法的第4~6行 while循环每次迭代开始的时候,子数组 A[1..A.heap-size]要满足最大堆的性质.如果 ...
- Django日志输出
# 自定义日志输出信息 LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 'standard': ...