01 背包例题(二维数组+滚动数组优化)

简介: 01 背包例题(二维数组+滚动数组优化)

01 背包


有N件物品和⼀个最多能被重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装⼊背包里物品价值总和最大?


1. 例题(二维数组解法)

题目

背包最大重量为4


重量 价值
物品0 1

15

物品1

3

20

物品2

4

30

问:背包能背的物品最大价值是多少?


思路

五部曲


1.数组含义


使用二维数组 dp[i][j],含义:从下标为 [ 0 ∼ i ] 的物品中任意取,放入容量为 j jj 的背包,价值总和最大为多少

2.递推公式由两个方向推出


一、不放物品 i 的最大价值

背包容量为 j,但不放物品 i 时的最大价值,即 dp[i-1][j]

二、放物品 i 的最大价值

先找到 dp[i-1][j-weight[i]],含义:i − 1 保证了不放物品 i,背包容量为 j − w e i g h t [ i ]  其实就是为了给后续放物品 i 一个预留量,保证放了物品 i ii 后背包不会溢出,所以最大价值为 dp[i-1][j-weight[i]]+value[i]

递推公式:

d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] )

3.数组初始化

背包容量 j jj 为零时,显然价值为零

只选物品0,即第一行,显然只要物品0重量小于等于背包重量 j jj,价值就为物品0的价值,否则为零


4.确定遍历顺序

先遍历背包还是物品都可以

dp[i][j] 所需的数据在其左上方


5.测试用例



代码展示

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
void test_2_wei_bag_problem1()
{
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;
    vector<vector<int>> dp(weight.size() + 1, vector<int>(bagWeight + 1));
    for (int i = 1; i < bagWeight + 1; i++)
    {
        if (weight[0] <= i)
        {
            dp[0][i] = value[0];
        }
    }
    for (int j = 1; j < bagWeight + 1; j++)
    {
        for (int i = 1; i < weight.size(); i++)
        {
            if (j < weight[i])
            {
                dp[i][j] = dp[i - 1][j];
            }
            else
            {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
            }
        }
    }
    cout << dp[weight.size() - 1][bagWeight];
}
int main()
{
    test_2_wei_bag_problem1();
    return 0;
}


2. 例题(滚动数组解法)

还是之前的例子,可以用滚动数组将数组降为一维

d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] )


由递推公式得: dp[i][j] 只和它的上一行有关,且有关元素的行数为 i − 1 i-1i−1,列数 ≤ j \le j≤j。那么我们就可以将数组压缩成一维

dp[i1][jweight[i]]

dp[i1][j]


欲求元素


看这张表,如果数组是一维的情况,那么在算出欲求元素后,其实是将欲求元素覆盖掉 dp[i-1][j],并且我们的遍历顺序也要改变。在二维情况下,我们是按从左到右的顺序求的,但在一维中,必须从右向左!因为在求欲求元素时,我们要保证 dp[i-1][j-weight[i]] 未被覆盖!同时,必须按照先遍历物品,再嵌套遍历背包的顺序。

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
void test_1_wei_bag_problem1()
{
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;
    vector<int> dp(bagWeight + 1);
    for (int i = 0; i < weight.size(); i++)
    {
        for (int j = bagWeight; j >= weight[i]; j--)
        {
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[bagWeight];
}
int main()
{
    test_1_wei_bag_problem1();
    return 0;
}
目录
相关文章
一文读懂Can总线错误处理
一文读懂Can总线错误处理
一文读懂Can总线错误处理
|
弹性计算 Linux
阿里云ECS磁盘在线扩容
阿里云ECS磁盘在线扩容
1581 0
|
存储 前端开发 JavaScript
最适合新手学习的react案例-Todolist尊享版!
【8月更文挑战第13天】最适合新手学习的react案例-Todolist尊享版!
199 2
最适合新手学习的react案例-Todolist尊享版!
|
JSON API 开发者
GET方式请求速卖通平台API 接口:商品列表数据获取指南
速卖通商品列表数据接口(如 `aliexpress.item_search`)让开发者获取商品信息列表, 包括名称、价格等关键数据。接口支持按关键词、分类ID等条件获取商品列表及详细信息, 并可通过分页与排序优化展示效果。开发者需在速卖通开放平台注册并创建应用获取API密钥, 构建HTTP请求并处理JSON响应数据。[体验API](http://b.mrw.so/2Pv6Qu)。
|
数据可视化 API
【Qt 学习笔记】Qt常用控件 | 多元素控件 | Tree Widget的说明及介绍
【Qt 学习笔记】Qt常用控件 | 多元素控件 | Tree Widget的说明及介绍
724 2
|
Arthas NoSQL Java
一次访问Redis延时高问题排查与总结(2)
本文是一次访问Redis延时高问题排查与总结的续篇,主要讲述了当时没有发现的一些问题和解决方案。
47897 22
|
Go API Docker
最简单的Go Dockerfile编写姿势,没有之一!
最简单的Go Dockerfile编写姿势,没有之一!
|
NoSQL 大数据 物联网
助力工业物联网,工业大数据之服务域:AirFlow的介绍【三十一】
助力工业物联网,工业大数据之服务域:AirFlow的介绍【三十一】
303 0
外贸出口单据之:PI(Proforma Invoice)
外贸出口单据之:PI(Proforma Invoice)
2295 1
|
消息中间件 数据可视化 API
rocketmq中可视化和池化
rocketmq获取默认的MQAdminExt时候,需要进行对象的获取,主要在rocketmq可视化中,方便使用,池化作为一个循环利用的过程,其类似于我们常用的数据库连接池一样,节省启动的成本。同时MQAdminExt是作为二次开发的一个主要使用的类。
662 0
rocketmq中可视化和池化