动态规划-背包问题

动态规划-背包问题背包问题是一种组合优化的NP完全问题。有N个物品和容量为W的背包,每个物品都有自己的体积w和价值v,求拿哪些物品可以使得背包所装下的物品的总价值最大。如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题;如果不限定wu’pi…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

背包问题是一种组合优化的NP完全问题。有N个物品和容量为W的背包,每个物品都有自己的体积w和价值v,求拿哪些物品可以使得背包所装下的物品的总价值最大。如果限定每种物品只能选择0个或1个,则问题称为0-1背包问题;如果不限定物品的数量,则问题称为“无界背包或完全背包”问题。

一、0-1背包问题

可以用动态规划来解决背包问题。以0-1背包为例。我们可以定义一个二维数组dp存储最大值,其中dp[i][j]表示前i件物品体积不超过j的情况下能达到的最大价值;如果我们将物品i放入背包,假设第i件物品体积为w,价值为v,那么我么能得到dp[i][j] = dp[i – 1][j – w] + v, 只需要在便利过程中对着两种情况取最大值即可,总时间和空间复杂度都为O(NW)。

int knapsack(vector<int> weights, vector<int> values, int N, int W) {
    vector<vector<int>> dp(N + 1, vector<int>(W + 1, 0));
    for (int i = 1; i <= N; i++) {
        int w = weights[i - 1], v = values[i - 1];
        for (int j = 1; j <= W; j++) {
            if (j >= w) {
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w] + v);
            }
            else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    return dp[N][W];
}

动态规划-背包问题

0-1背包问题-状态转移矩阵样例

 

可以进一步对0-1背包进行空间优化,将复杂度降低为O(W)。如图所示,假设我们目前考虑物品i=2, 且其体积为w=2, 价值为v=3;对于背包容量j,我们可以得到dp[2][j] = max(dp[1][j], dp[1][j – 2] + 3)。 可以发现我们永远只依赖于上一排i=1的信息,之前算过的其他物品都不需要再使用。因此我们可以去掉dp矩阵的第一个维度,在考虑物品i时变成dp[j] = max(dp[j], dp[j-w] + v)。 这里注意需要逆向便利,这样才能够调用上一行物品i-1时 dp[j-w]的值;若按照从左往右的顺序进行正向遍历,则dp[j-w]的值在遍历到j之前就已经背更新成物品i的值了。

int knapsack(vector<int> weights, vector<int> values, int N, int W) {
    vector<int> dp(W + 1, 0);
    for (int i = 1; i <= N; ++i) {
        int w = weights[i - 1], v = values[i - 1];
        for (int j = W; j >= w; j--) {
            dp[j] = max(dp[j], dp[j - w] + v);
        }
    }
    return dp[W];
}

 

二、完全背包问题

完全背包问题中,一个物品可以拿多次。如下图所示:

动态规划-背包问题

假设我们便利到物品i=2, 且其体积为w=2, 价值为v=3; 对于背包容量j = 5, 组多只能装下2个该物品。那么我们的状态转移方程就变成了dp[2][5] = max(dp[1][5], dp[1][3] + 3, dp[1][1] + 6)。 如果采用这种方法,假设背包容量无穷大而物体的体积无穷小,我们这里的比较次数也会趋近于无穷大,远超O(NW)的时间复杂度。

怎么解决这个问题呢?我们发现在dp[2][3]的似乎和其实已经考虑过了dp[1][3]和dp[2][1]的情况,而在dp[2][1]的时候也已经考虑过dp[1][1]的情况。因此如下图所示:

动态规划-背包问题

对于拿多个物品的情况,我们只需要考虑dp[2][3]即可,即dp[2][5] = max(dp[1][5], dp[2][3]+3). 这样就得到了完全背包问题的状态转移方程:

dp[i][j] = max(dp[i – 1][j], dp[i][j-w] +v), 其与0-1背包问题的差别仅仅是把状态转移方程中的第二个i-1变成了i。

int knapsack(vector<int> weights, vector<int> values, int N, int W) {
    vector<vector<int>> dp(N + 1, vector<int>(W + 1, 0));
    for (int i = 1; i <= N; i++) {
        int w = weights[i - 1], v = values[i - 1];
        for (int j = 1; j <= W; j++) {
            if (j >= w) {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - w] + v);
            }
            else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    return dp[N][W];
}

同样的,我们也可以利用空间压缩将时间复杂度降低为O(W)。这里注意哦我们在便利每一行的时候必须正向便利,因为我们要利用当前物品在第j-w列的信息。

int knapsack(vector<int> weights, vector<int> values, int N, int W) {
    vector<int> dp(W + 1, 0);
    for (int i = 1; i <= N; i++) {
        int w = weights[i - 1], v = values[i - 1];
        for (int j = w; j <= W; j++) {
            dp[j] = max(dp[j], dp[j - w] + v);
        }
    }
    return dp[W];
}

注意:压缩空间到底需要正向还是逆向遍历呢?物品和体积哪个放在外曾,哪个放在内层呢?这取决与状态转移方程的依赖关系。在思考空间压缩之前,不妨将转移矩阵画出来,方便思考如何进行空间压缩。

如果实在不想仔细思考,有个简单的口诀:0-1背包对物品的迭代放外层,里层的体积或值逆向遍历;完全背包对物品的迭代放里层,外层的体积或价值正向遍历。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/164398.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Celer Network月报 202107

    Celer Network月报 202107Celer技术研发更新 cBridgev1开发完成,主网上线,运行良好 cBridgev2开始研发,新增智能费率与流动性调节功能 Layer2.finance测试网成功运行,完成所有相关问题修复与功能改进 正在进行多项Layer2.finance的策略开发工作 SGN主网技术支持,现已有10个验证节点上线 Celer社区建设及市场活动社区动态更新本月重点事件Layer2.financev1.0版本测…

  • C语言实现五子棋小游戏

    C语言实现五子棋小游戏三子棋,五子棋,无论多少子棋,其原理都是一样的。下面我用五子棋为例讲解用C语言多文件编程实现五子棋。设计电脑和玩家两个作为下棋的两方,用键盘输入作为玩家的游戏操作。1.效果图:程序总的构架:我们只要输入坐标就可以和电脑对弈了。电脑的棋子用‘0’表示,玩家的棋子用‘x’表示。2.打印菜单可以根据自己的爱好设计各种风格的…

  • MAC 系统安装 Maven 及环境变量配置

    MAC 系统安装 Maven 及环境变量配置1、概述本文主要为在MAC苹果系统下安装Maven及环境变量配置Maven是Apache下的一个纯Java开发的开源项目。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。Maven是一个项目管理工具,可以对Java项目进行构建、依赖管理。Maven也可被用于构建和管理各种项目,例如C#,Ruby,Scala和其他语言编写的项目。Maven曾是Jakarta项目的子项目,现为由Apache软件基金会主持

  • step by step guide tell you how to build a website like apkmirror

    step by step guide tell you how to build a website like apkmirrorTherearemanyfreeapkdownloadwebsitessuchasapkmirror,todayiwilltellyouhowtobuildawebsitelikeapkmirror,theprogramminglanguageiusedisnode.js,thedatabaseiusedismongodb,searchengineusediselasticsearch,thewebframeworki.

    2022年10月23日
  • 2021-09-27 网安实验-取证分析-数字取证之foremost

    2021-09-27 网安实验-取证分析-数字取证之foremostForemost的使用关于foremostForemost是基于文件开始格式,文件结束标志和内部数据结构进行恢复文件的程序Foremost参数说明$foremost[-v|-V|-h|-T|-Q|-q|-a|-w-d][-t][-s][-k][-b][-c][-o][-i<file]-V-显示版权信息并退出-t-指定文件类型.(-tjpeg,pdf…)-d-打开间接块检测(针对UNIX文件系统)-i-指定输入文件(默认为标准输

    2022年10月24日
  • vs2015激活成功教程密钥_vs2015产品激活密钥

    vs2015激活成功教程密钥_vs2015产品激活密钥对于开发者而言,一款优秀智能的开发工具能够提升应用开发的效率,正因为如此,VisualStudio作为主流的开发工具,微软非常的用心,不仅能够让这款开发工具满足用户体验的需要,同时能够支持更多的新技术架构,并且,VS2012更加适合用于开发Windows8专用程序。网上好多无效的,为了收藏,先保存一份。一、VS2012下载地址。中文版:http://download….

    2022年10月14日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号