背包问题的分类


01背包问题

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

在求选 第 i 个物品的状态转移方程的时候,我们可以取出  的最大值再加上 w[i]

不选第 i 个物品的话,状态转移方程就是 


#include <iostream>
#include <cstring>
using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N][N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ )for(int j = 0; j <= m; j ++ ){f[i][j] = f[i - 1][j];if(j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);}cout << f[n][m] << endl;return 0;
}

从二维优化到一维

通过  DP 的状态转移方程,我们发现,每一阶段的 i 的状态只与上一阶段的 i-1 的状态有关。在这种情况下,可以使用称为“滚动数组”的优化方法,降低时间开销。

因为  这里的  一定比  更早计算出来,所以  计算得到的是第 i 层的,而在我们上述的 DP 方程中,所用的是第 i - 1 层的数据,所以如果是从小到大遍历体积的话,会出现 “数据污染” 的情况。所以体积的枚举要从大到小来枚举。

一维优化代码实现

#include <iostream>
#include <cstring>
using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];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]);}cout << f[m] << endl;return 0;
}

完全背包问题

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10

 

对于朴素做法有:   类比01背包问题

代码实现

#include <iostream>
#include <algorithm>
using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N][N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ )for(int j = 0; j <= m; j ++ )for(int k = 0; k * v[i] <= j; k ++ )f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);cout << f[n][m] << endl;return 0;
}

通过比较下列等式可以发现:

得到:

#include <iostream>
#include <algorithm>
using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N][N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ )for(int j = 0; j <= m; j ++ ){f[i][j] = f[i - 1][j];if(j >= v[i]) f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);}cout << f[n][m] << endl;return 0;
}

一维优化

#include <iostream>
#include <algorithm>
using namespace std;const int N = 1010;int n, m;
int v[N], w[N];
int f[N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];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]);}cout << f[m] << endl;return 0;
}

对比01背包完全背包问题,有以下差异 :

01背包:

完全背包:

对于完全背包来说,体积的枚举可以从 v[i] 枚举到 m,因为它每 i 层的更新使用的是第 i 层的数据不存在“数据污染”的问题


多重背包问题

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

 


朴素写法

#include <iostream>
#include <algorithm>
using namespace std;const int N = 110;int n, m;
int v[N], w[N], s[N];
int f[N][N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];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 ++ )f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);cout << f[n][m] <<  endl;return 0;
}

多重背包的二进制优化

众所周知,从  这 k 个2的整数次幂中选出若干个相加,可以表示出  之间的任意整数。进一步的,我们求出满足  的最大整数 p,设 那么:

  1. 根据 p 的最大性,有  ,可推出 ,因此  选出若干个相加可以表示出  之间的任意整数;
  2. 从  中选出若干个相加,可以表示出  之间的任何整数,而根据 Ri 的定义, ,因此, 选出若干个可以表示出 之间的任意整数。

综上所述,我们可以把数量为  的第 i 个物品拆成 p + 2个物品,他们的体积分别为:

这 p + 2 个物品可以凑成  之间所有能被Vi整除的数,并且不能凑成大于 Ci * Vi 的数。这等价于原问题中体积为 Vi 的物品可以使用 0~Ci 次。该方法仅将每种物品拆分成了  个,效率较高。

代码实现

#include <iostream>
#include <algorithm>
using namespace std;const int N = 25000, M = 2010;int n, m;
int v[N], w[N];
int f[N];int main()
{cin >> n >> m;int cnt = 0;for(int i = 1; i <= n; i ++ ){int a, b, s;cin >> a >> b >> s;int k = 1;while(k <= s){cnt ++ ;v[cnt] = a * k;w[cnt] = b * k;s -= k;k *= 2;}if(s > 0){cnt ++;v[cnt] = a * s;w[cnt] = b * s;}}n = cnt;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]);cout << f[m] << endl;return 0;
}

分组背包问题

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8


AC代码

#include <iostream>
#include <algorithm>
using namespace std;const int N = 110;int n, m;
int v[N][N], w[N][N], s[N];
int f[N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ ){cin >> s[i];for(int j = 0; j < s[i]; j ++ )cin >> v[i][j] >> w[i][j];}for(int i = 1; i <= n; i ++ )for(int j = m; j >= 0; j -- )for(int k = 0; k < s[i]; k ++ )if(v[i][k] <= j)f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);cout << f[m] << endl;return 0;
}

【动态规划】—— 背包问题相关推荐

  1. 贪婪算法、递归计算、动态规划背包问题

    //贪婪算法计算背包问题public static double ksack(double[] values, double[] weights, int capacity){double load ...

  2. 动态规划——背包问题(01背包问题)

    动态规划--背包问题(01背包问题) 01背包问题(求最大价值): 问题优化 01背包问题(求方案数): 动态规划--背包问题(01背包问题) 01背包问题(求最大价值): 有N件物品和一个最多能背重 ...

  3. 动态规划背包问题优化空间复杂度——滚动数组

    动态规划背包问题优化空间复杂度--滚动数组 背包问题 空间复杂度优化 Java代码 链接:代码随想录背包问题 背包问题   背包问题是动态规划中基本的问题,我们考虑下面的简单问题:   假设背包容量为 ...

  4. 动态规划——背包问题(详解)

    动态规划是我最早接触的算法,一开始非常简单,固定模板题,后来愈发愈发难起来了,条件,状态压缩等等,难点主要是,状态怎么表示,状态转移方程怎么写,这篇文章将会从背包五大问题详解,希望能帮助到大家去类比, ...

  5. 动态规划——背包问题

    动态规划--背包问题 对于背包问题,今天我们先讲解,01背包,完全背包,和多重背包.我主要从: 什么题可以用背包问题解决 背包问题的模板细节,如何准确写出背包. 1.什么题可以用背包问题解决 看到题目 ...

  6. 动态规划背包问题详解(二)---0-1背包问题

    /**  * 对于技术面试,你还在死记硬背么?  * 快来"播"沙糖橘吧,  * 用视频案例为你实战解读技术难点  * 聚焦Java技术疑难点,实战视频为你答疑解惑  * 越&qu ...

  7. 【入门级】Java解决动态规划背包问题

    目录 前言 动态规划背包问题是什么? 动态规划解题转代码 第一步:拆包填表格 第二步:转为代码 一.首先看空表格:即初始化代码 二.看怎么循环填表格 三.输出结果(最大价值) 第三步:完整代码 动态规 ...

  8. Java-算法-动态规划-背包问题

    看完本篇文章可以再多练习相似题目 算法-动态规划-背包问题-附一 ​​​​​​​ 一. 背包问题介绍 1. 最原始的背包问题 给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择 ...

  9. 动态规划---背包问题分析

    0/1背包 问题描述 有N件物品和一个容量为V的背包,第i件物品的体积为c[i],价值为w[i].求将哪些物品放进背包可以使物品价值总和最大(有两种情况:不要求填满背包和填满背包). 每件商品只有一件 ...

  10. 动态规划 —— 背包问题 P09 —— 背包问题的变化

    [输出方案] 一般而言,背包问题是要求一个最优值,如果要求输出这个最优值的方案,可以参照一般动态规划问题输出方案的方法:记录下每个状态的最优值是由状态转移方程的哪一项推出来的,换句话说,记录下它是由哪 ...

最新文章

  1. python启动jupyter_如何在启动JupyterNotebook时自动执行代码?
  2. java foreach标签,jstl c:foreach标签
  3. 良/恶性乳腺癌肿瘤预测
  4. C++ sizeof总结
  5. linux 文件系统原理 书,发个关于文件系统的书《Linux文件系统剖析》
  6. 《Go语言程序设计》读书笔记(十)反射
  7. 解决JS拖拽出现的问题
  8. 数据库学习--MySQL锁
  9. 《Android框架揭秘》——2.2节搭建Android平台编译环境
  10. 观天涯kk大神10年帖子有感
  11. 指纹识别技术相比于其它生物识别技术,有哪些优缺点?
  12. VS本地项目如何发布到服务器详细流程(IIS部署 发布网站)
  13. 科属种XML文档三级树状图浏览的实现
  14. JQuery从入门到实战
  15. 头歌Python实训答案——函数结构
  16. 内存缓存和LruCache
  17. 错误:App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insec
  18. vb html listview,VB中listview控件
  19. 用python动手学统计学_3-5样本统计量的性质
  20. C# winform PictureBox插入图片并设置自适应显示

热门文章

  1. 了解Oracle RAC Brain Split Resolution集群脑裂协议
  2. 水果店需要的设备清单有哪些,水果店都需要哪些设备
  3. Koch Curve
  4. 所有的时间伟大的好莱坞电影大片
  5. Python 错误:Workbook corruption: seen[2] == 4解决
  6. cd src make install make[1]: Entering directory `/home/xuweiliang/redis/r 错误解析
  7. 删除MAC系统自带的ABC输入法[亲测]
  8. css3中的2D和3D转换、动画效果以及布局
  9. 买笔记本电脑的注意事项
  10. oracle user does not exist,user 'scott' does not exist! 又学了一招