首页 > 其他分享 >01背包问题

01背包问题

时间:2022-10-05 18:12:06浏览次数:72  
标签:01 int max 问题 背包 体积 物品 dp

问题描述

01背包问题
有\(N\)件物品和一个容量是\(V\)的背包,每件物品只能使用一次。

第\(i\)件物品的体积是\(v_i\),价值是\(w_i\),求解将哪些物品装入背包,可使这些物品总体积不超过背包容量,并且总价值最大。

解题思路

动态规划的经典例题,首先考虑dp[i][j]的含义,这里i表示只考虑前i个物品(i从\(1\sim N\)),dp[i][j]表示总体积为j的情况下,考虑前i个物品时,背包里的物品的最大价值。

可以分成两种情况考虑dp[i][j]的递推关系:

  • i个物品不在背包中时,dp[i][j] = dp[i - 1][j]
    • 此时只有前i - 1个物品,背包中物品体积仍为j
  • i个物品在背包中时,dp[i][j] = dp[i - 1][j - v[i]] + w[i]
    • i - 1个物品的体积为j - v[i]

初始化,显然dp[0][0] = 0

根据递推关系和初始化条件写for循环遍历即可。

代码

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
const int N = 1010; // 体积不超过1000, 物品件数也不超过1000

int main() {
    int n, m; // n为物品数量,m为背包体积
    cin >> n >> m;
    int dp[N][N] = {0};
    int v[N] = {0}; // 体积
    int w[N] = {0}; // 价值
    for (int i = 1; i <=n; i++)
        cin >> v[i] >> w[i];
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j >= v[i]) // 当前总体积肯定不能小于v[i],如果小于的话,第i个物品不能放
                dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
        }
    }
    // int res = 0;
    // for (int j = 1; j <=m; j++) {
    //     res = max(res, dp[n][j]); // 不需要遍历,直接输出dp[n][m]即可
    // }
    cout << dp[n][m] << endl;
    return 0;
}

优化

分析上面的代码,实际上dp[i][j]递推时只会用到dp[i - 1][j],而不会用到dp[i - 2][j], dp[i - 3][j]等,因此dp数组实际上只需要一维即可,索引为当前总体积。

那么,是否可以直接写成

for (int i = 1; i < n; i++) {
    for (int j = 1; j <= m; j++)
        if (j >= v[i])
            // 这里的max实际上是
            // max(dp[i][j], dp[i][j - v[i]] + w[i])
            dp[j] = max(dp[j], dp[j - v[i]] + w[i]);  
}

不可以!原因已在上面的代码里的注释中给出,应该是max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i])才对。

正确的写法应该是:

for (int i = 1; i <= n; i++) {
    for (int j = m; j >= v[i]; j--)
        // 因为dp[j], dp[j - v[i]]只在上一次的i循环中才被赋值了,
        // 所以这里用的实际上是dp[i - 1][j - v[i]]
        dp[j] = max(dp[j], dp[j - v[i]] + w[i]); 
}

如果dp[0] = 0, dp[i] = -INF,那么状态只能从dp[0]转移过来,可以求解总体积恰为\(V\)的情况。

优化后的完整代码:

#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
const int N = 1010; // 体积不超过1000, 物品件数也不超过1000

int main() {
    int n, m; // n为物品数量,m为背包体积
    cin >> n >> m;
    int dp[N] = {0};
    int v[N] = {0}; // 体积
    int w[N] = {0}; // 价值
    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--) {
                // 当前总体积肯定不能小于v[i],如果小于的话,第i个物品不能放
                dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
        }
    }
    // int res = 0;
    // for (int j = 1; j <=m; j++) {
    //     res = max(res, dp[n][j]); // 不需要遍历,直接输出dp[n][m]即可
    // }
    cout << dp[m] << endl;
    return 0;
}

例题

标签:01,int,max,问题,背包,体积,物品,dp
From: https://www.cnblogs.com/zwyyy456/p/16756048.html

相关文章

  • luogu P3822 [NOI2017] 整数
    Link题解这里有一个很傻逼的无脑做法:https://www.luogu.com.cn/blog/80614/solution-p3822正常的正解做法是考虑用线段树维护每一位是什么,然后将\(a\)拆成二进制位,对......
  • luogu P3644 [APIO2015] 八邻旁之桥
    Link题解首先忽略掉同侧的询问。对于\(K=1\),它其实就是问一个点到其它点的距离之和最小值,直接找到中位数然后计算即可。对于一条路线,我们可以发现,如果建的桥里这两个......
  • Three.js day01
    `<head><metacharset="UTF-8"><title>第一个three.js文件_WebGL三维场景</title><style>body{margin:0;overflow:hidden;/*隐......
  • 记一次SpringBoot中跨域的小问题
    记一次SpringBoot中跨域的小问题问题前阵子,有个学长在跨域的时候遇到一个问题,我们两个人互相讨论了一番,得到了问题的答案。问题如下:如果按照上图的方式配置跨域类,那么......
  • 关闭sysMain服务解决win10系统硬盘占用率莫名增加到100%的卡顿问题
    最近电脑打游戏莫名会卡顿,甚至平常使用电脑都会感到卡顿感。打开任务管理器,看到硬盘占用率会突然涨到100%关闭superfetch服务后,卡顿问题得到解决。SysMain服务禁用方法:......
  • 1014 福尔摩斯的约会
     题目: 大侦探福尔摩斯接到一张奇怪的字条:我们约会吧!3485djDkxh4hhGE2984akDfkkkkggEdsbs&hgsfdkd&Hyscvnm 大侦探很快就明白了,字条上奇怪的乱码实际上就......
  • mysql 的小问题
    首先按下win+R执行services.msc进入服务,查找到MySQL,点击停止服务,然后在控制台cmd进入本地的MySQL文件夹,我的文件名是mysql-8.0.26-winx64,进入后执行命令scdeletemysql......
  • texlive编译中发现字体有问题解决
    这里可以用tlmgrinfo命令搜索需要下载的字体并从CTAN官网下载。一般这个时候也会有对应的路径,比如texmf-dist/fonts/。把下载的字体解压放在这些路径下,然后分别运行mktexl......
  • 重识Nginx - 01 Nginx 主要应用场景及版本概述
    文章目录​​Nginx的三个主要应用场景​​​​静态资源服务​​​​反向代理服务​​​​API服务​​​​WhyNginx​​​​Nginx的优点​​​​Nginx本发布情况(mainline......
  • Closed-loop Matters: Dual Regression Networks for Single Image Super-Resolution
    第一遍:摘要:现有的SR方法有两个潜在的限制:首先,学习从LR到HR图像的映射函数通常是一个病态问题,因为存在无限个HR图像可以下采样到相同的LR图像;其次,配对的LR-HR数据在现实应......