背包问题学习笔记 / Dynamic Programming(updating)
01背包问题
朴素版:(二维数组)
状态表示: dp[i][j]:从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案(n:物品数量,m:最大体积)
状态计算: dp[i][j] = max ( dp[i-1][j] , dp[i-1][j-vi]+wi ) // 由含i和不含i两个子集合计算而来(vi:物品体积,wi:物品价值)
核心代码:
int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
if(v[i] >= j) dp[i][j] = max(dp[i][j], dp[i-1][j-v[i]] + w[i]);
}
}
空间优化版:(滚动数组,二维数组优化至一维)
状态表示:dp[j]:在外循环的第i层时,表示从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,n层循环后,dp[m]就是最终答案
状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi ) // 由含i和不含i两个子集合计算而来
核心代码:
int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N]; void keyCode()
{
for(int i = 1; i <= n; i++)
// 反向遍历, 否则dp[j-v[i]]可能为dp[i][j-v[i]](用更新后的值来更新导致出错)
for(int j = m; j >= v[i]; j--)
dp[j] = max(dp[j], dp[j-v[i]] + w[i]); }
完全背包问题
朴素版:(二维数组)
状态表示:dp[i][j]:从前i种物品中选择(每种物品可以任选个数)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案
状态计算:dp[i][j] = max ( dp[i-1][j] , dp[i][j-vi]+wi )
证明:dp[i][j] = max ( dp[i-1][j] , dp[i-1][j-vi]+wi , dp[i-1][j-2vi]+2wi , dp[i-1][j-3vi]+3wi , ...... )
dp[i][j-vi] = max ( dp[i-1][j-vi] , dp[i-1][j-2vi]+wi , dp[i-1][j-3vi]+2wi , ...... )
Thus,dp[i][j-vi]+wi = max ( dp[i-1][j-vi]+wi , dp[i-1][j-2vi]+2wi , dp[i-1][j-3vi]+3wi , ...... )
Thus,dp[i][j] = max ( dp[i-1][j] , dp[i][j-vi]+wi )
核心代码:
int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
if(j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j-v[i]] + w[i]);
}
}
空间优化版:(滚动数组,二维数组优化至一维)
状态表示:dp[j]:在外循环的第i层时,表示从前i种物品中选择(每种物品可以任选个数)且总体积不超过j的集合的最大价值,n层循环后,dp[m]就是最终答案
状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi ) // 由含i和不含i两个子集合计算而来
核心代码:
int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N]; void keyCode()
{
for(int i = 1; i <= n; i++)
// 正向遍历, 使得dp[j-v[i]]为dp[i][j-v[i]]
for(int j = v[i]; j <= m; j++)
dp[j] = max(dp[j], dp[j-v[i]] + w[i]); }
多重背包问题
朴素版:(二维数组+三重循环)
状态表示:dp[i][j]:从前i种物品中选择(每种物品最多选择si个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案
状态计算:dp[i][j] = max ( dp[i-1][j],dp[i-1][j-v]+w,dp[i-1][j-2v]+2w,...,dp[i-1][j-sv]+sw )
核心代码:
int n, m; // n:物品数量, m:最大体积
int v[N], w[N], s[S];
int dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
for(int k = 0; k <= s[i] && k * v[i] <= j; k++)
dp[i][j] = max(dp[i][j], dp[i-1][j-k*v[i]] + k*w[i]);
}
优化版:(一维数组+二重循环)
二进制优化:对于每种物品,将其按2的次幂大小拆分合并,如s[i]=12时,方案为:第1个物品合并,第2~3个物品合并,第4~7个物品合并,第8~12个物品合并(1,2,4,5)。这样,就将多重背包问题转化成01背包问题
状态表示:dp[j]:在外循环的第i层时,表示从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,n层循环后(n为问题转化后的新n),dp[m]就是最终答案
状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi )
核心代码:
int n, m;
int v[N], w[N], dp[M]; // N:maxn * logmaxs void keyCode()
{
int cnt = 0;
for(int i = 1; i <= n; i++)
{
int a, b, s; // vi, wi, si
cin >> a >> b >> s;
int p = 1;
while(p <= s)
{
cnt ++;
v[cnt] = a * p, w[cnt] = b * p;
s -= p, p *= 2;
}
if(s > 0)
{
cnt ++;
v[cnt] = a * s, w[cnt] = b * s;
}
}
n = cnt; // n --> 问题转化后的新n
for(int i = 1; i <= n; i++)
for(int j = m; j >= v[i]; j--) // 反向遍历
dp[j] = max(dp[j], dp[j-v[i]] + w[i]);
}
分组背包问题
朴素版:(二维数组)
状态表示:dp[i][j]:从前i组物品中选择(每组物品中只能选择0或1个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案
状态计算:dp[i][j] = max ( dp[i-1][j],dp[i-1][j-vi,1]+wi,1,dp[i-1][j-vi,2]+wi,2,dp[i-1][j-vi,3]+wi,3,... )
核心代码:
int n, m; // n:物品数量, m:最大体积
int s[N], v[N][S], w[N][S];
int dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
for(int k = 1; k <= s[i]; k++)
if(v[i][k] <= j)
dp[i][j] = max(dp[i][j], dp[i-1][j-v[i][k]] + w[i][k]);
}
}
}
空间优化版:(滚动数组,二维数组优化至一维)
int n, m; // n:物品数量, m:最大体积
int s[N], v[N][S], w[N][S];
int dp[M]; void keyCode()
{
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= 0; j--) // 反向遍历
{
for(int k = 1; k <= s[i]; k++)
if(v[i][k] <= j)
dp[j] = max(dp[j], dp[j-v[i][k]] + w[i][k]);
}
}
}
背包问题学习笔记 / Dynamic Programming(updating)的更多相关文章
- angular2 学习笔记 ( Dynamic Component 动态组件)
更新 2018-02-07 详细讲一下 TemplateRef 和 ViewContainerRef 的插入 refer : https://segmentfault.com/a/1190000008 ...
- DP背包问题学习笔记及系列练习题
01 背包: 01背包:在M件物品中取出若干件物品放到背包中,每件物品对应的体积v1,v2,v3,....对应的价值为w1,w2,w3,,,,,每件物品最多拿一件. 和很多DP题一样,对于每一个物品, ...
- 动态规划 Dynamic Programming 学习笔记
文章以 CC-BY-SA 方式共享,此说明高于本站内其他说明. 本文尚未完工,但内容足够丰富,故提前发布. 内容包含大量 \(\LaTeX\) 公式,渲染可能需要一些时间,请耐心等待渲染(约 5s). ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图 代码工程地址: https://github.c ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader) 代码工程 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二) 代码工程地址: https:/ ...
- Dynamic CRM 2013学习笔记 系列汇总
这里列出所有 Dynamic CRM 2013学习笔记 系列文章,方便大家查阅.有任何建议.意见.需要,欢迎大家提交评论一起讨论. 本文原文地址: Dynamic CRM 2013学习笔记 系列汇总 ...
- IOS学习笔记之关键词@dynamic
IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...
- Dynamic CRM 2013学习笔记(一)插件输入实体参数解析
1. 问题描述 最近新建了一个post事件的插件,传入的参数处理如下: 1: if (context.InputParameters.Contains("Target") &a ...
随机推荐
- CentOS 并没有死,Rocky Linux 让其重生
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 近日,CentOS 官方发文称CentOS Stream ...
- 关于前端ajax请求获取数据成功之后无法操作数据的原因及解决方法
前言:做项目的时候我用ajax请求json数据,遍历使用数据时却发现页面无响应.关于这个问题今天有个朋友又问了我一次,记录一下.由于我没有记录,这里用我朋友的图片. 代码现象: 这里他是使用alert ...
- c++:-7
上一节主要学习C++中的函数模版.数据结构以及排序查找操作:c++:-6,本节学习C++的范型程序设计和STL: 范型程序设计 编写不依赖于具体数据类型的程序 将算法从特定的数据结构中抽象出来,成为通 ...
- 关于Spring中的useSuffixPatternMatch
背景 spring-boot的版本是2.1.4.RELEASE,spring的版本是5.1.6.RELEASE 一个例子如下: @Configuration @Import(WebMvcAutoCon ...
- 如何生成一个java文档
如何生成一个java文档 众所周知,一个程序给别人看可能可以看懂,几万行程序就不一定了.在更多的时候,我们并不需要让别人知道我们的程序是怎么写的,只需要告诉他们怎么用的.那么,api文档就发挥了它的作 ...
- Spring Security之短信登录
实现短信验证码登录 前面实现了 用户名+密码 的登录方式,现在实现一下短信验证码登录. 开发短信验证码接口 短信验证码和图形验证码类似,用户从手机短信得到验证码和从图片得到验证码类似. 校验短信验证码 ...
- 论文解读(SCGC))《Simple Contrastive Graph Clustering》
论文信息 论文标题:Simple Contrastive Graph Clustering论文作者:Yue Liu, Xihong Yang, Sihang Zhou, Xinwang Liu论文来源 ...
- mysql外键与表查询
目录 自增特性 外键 外键关系 外键创建 外键的约束效果 级联更新级联删除 多对多关系 一对一关系 表查询关键字 select与from where筛选 group by分组 练习 关系练习 查询练习 ...
- python字符编码与文件操作
目录 字符编码 字符编码是什么 字符编码的发展史 字符编码实际应用 编码与解码 乱码问题 python解释器层面 文件操作 文件操作简介 文件的内置方法 文件的读写模式 文件的操作模式 作业 答案 第 ...
- break、continue、return中选择一个,我们结束掉它
在平时的开发过程中,经常会用到循环,在写循环的过程中会有很多判断条件及逻辑,你知道如何结束一个循环吗?在java中有break.continue.reture三个关键字都可以结束循环,我们看下他们 ...