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]+w, dp[i-1][j-2vi]+2wi , dp[i-1][j-3vi]+3w, ...... )

       dp[i][j-vi] = max (               dp[i-1][j-vi] ,      dp[i-1][j-2vi]+w,   dp[i-1][j-3vi]+2w,  ...... )

       Thus,dp[i][j-vi]+wi = max ( dp[i-1][j-vi]+wi , dp[i-1][j-2vi]+2w, dp[i-1][j-3vi]+3w,  ...... )

       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)的更多相关文章

  1. angular2 学习笔记 ( Dynamic Component 动态组件)

    更新 2018-02-07 详细讲一下 TemplateRef 和 ViewContainerRef 的插入 refer : https://segmentfault.com/a/1190000008 ...

  2. DP背包问题学习笔记及系列练习题

    01 背包: 01背包:在M件物品中取出若干件物品放到背包中,每件物品对应的体积v1,v2,v3,....对应的价值为w1,w2,w3,,,,,每件物品最多拿一件. 和很多DP题一样,对于每一个物品, ...

  3. 动态规划 Dynamic Programming 学习笔记

    文章以 CC-BY-SA 方式共享,此说明高于本站内其他说明. 本文尚未完工,但内容足够丰富,故提前发布. 内容包含大量 \(\LaTeX\) 公式,渲染可能需要一些时间,请耐心等待渲染(约 5s). ...

  4. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图 代码工程地址: https://github.c ...

  5. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader)

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十三章:计算着色器(The Compute Shader) 代码工程 ...

  6. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二)

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第七章:在Direct3D中绘制(二) 代码工程地址: https:/ ...

  7. Dynamic CRM 2013学习笔记 系列汇总

    这里列出所有 Dynamic CRM 2013学习笔记 系列文章,方便大家查阅.有任何建议.意见.需要,欢迎大家提交评论一起讨论. 本文原文地址: Dynamic CRM 2013学习笔记 系列汇总 ...

  8. IOS学习笔记之关键词@dynamic

    IOS学习笔记之关键词@dynamic @dynamic这个关键词,通常是用不到的. 它与@synthesize的区别在于: 使用@synthesize编译器会确实的产生getter和setter方法 ...

  9. Dynamic CRM 2013学习笔记(一)插件输入实体参数解析

      1. 问题描述 最近新建了一个post事件的插件,传入的参数处理如下: 1: if (context.InputParameters.Contains("Target") &a ...

随机推荐

  1. Linux进程总结

    一个执着于技术的公众号 进程 进程,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.它的执行需要系统分配资源创建实体之后,才能进行.举个例子: ...

  2. 测试覆盖率 之 Cobertura的使用

    什么是代码覆盖率? 代码覆盖率是对整个测试过程中被执行的代码的衡量,它能测量源代码中的哪些语句在测试中被执行,哪些语句尚未被执行. 为什么要测量代码覆盖率? 众所周知,测试可以提高软件版本的质量和可预 ...

  3. JZ008和大于等于target的最短数组

    title: 长度最小的子数组 题目描述 题目链接:长度最小的子数组.剑指offer008 解题思路 简单滑动窗口题目,需要知道: 窗口左指针移动条件:窗口内总和 ≥ target 即可以不断移动窗口 ...

  4. 【理论积累】C语言基础理论知识【第一版】

    第一个程序 #include <stdio.h> int main(){ printf("Hello World"); } 变量与常量 变量类型:整型[int].字符型 ...

  5. 用c++语言socket库函数实现服务端客户端聊天室

    客户端 /* * 程序名:client.cpp,此程序用于演示socket的客户端 * 作者:C语言技术网(www.freecplus.net) 日期:20190525 */ #include < ...

  6. 无线:SSID

    BSSID,SSID,ESSID区别   SSID(Service Set Identifier)   SSID,AP唯一的ID码,许多人认为可以将SSID写成ESSID,其实不然,SSID是个笼统的 ...

  7. 146_ACCESS之HR招聘信息管理_64位

    焦棚子的文章目录 点击下载附件 一.背景: 最近把之前做的一个HR招聘信息管理工具翻新了下,有需要的朋友可以自取,主要想解决的问题是多人在跟进人员招聘的时候信息的不对称,这样下来的就可以及时的看到整个 ...

  8. c++:-9

    上节(c++:-8)主要学习了C++的流类库和输入输出,本节学习C++的异常处理. 异常处理 介绍 (1)异常处理的基本思想: (2)异常处理的语法: (3)举例:处理除0异常 #include &l ...

  9. 安装Speedtest到Python

    Speedtest模块可以测试主机的网络带宽大小. 运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:无 硬件要求:无 安装过程 1.安装Spee ...

  10. 最强肉坦:RUST多线程

    Rust最近非常火,作为coder要早学早享受.本篇作为该博客第一篇学习Rust语言的文章,将通过一个在其他语言都比较常见的例子作为线索,引出Rust的一些重要理念或者说特性.这些特性都是令人心驰神往 ...