动规解决01背包/完全背包精讲

还不会用动态规划解决01背包/完全背包?看这一篇文章就够了!

首先我们要明白什么是01背包和完全背包。

背包问题总体问法就是:

你有一个背包,最多能容纳的体积是V。

现在有n个物品,第i个物品的体积为vi​ ,价值为wi​。

现在有n种物品,每种物品有任意多个,第i种物品的体积为vi​ ,价值为wi​。

(1)求这个背包至多能装多大价值的物品?

(2)若背包恰好装满,求至多能装多大价值的物品?

根据物品个数是唯一还是无限多个,如果只能装一个,就是01背包问题;如果同一个物品能装无限多个,就是完全背包问题。

问法的区别:

同样也是分为两类,第一种就是必须将背包恰好装满,第二种问法是背包不必装满。

在弄清楚什么是01背包和完全背包后,我们来正式学习如何解决这类问题吧!


我们首先来详细讲解01背包和完全背包的母题(模板),然后会有相应的例题,同样也有详解给到大家!

一、01背包

【模板】01背包_牛客题霸_牛客网 (nowcoder.com)

我们先解决第一问,背包没有必须装满的情况下。

用动态规划解决问题有下面的标准步骤:

1、状态表示:

dp[i][j] 表示从前i个物品中挑选,总体积不超过j,所有选法中能挑选出的最大价值。

有同学会问,状态表示为什么是这样的呢?因为这样我们会包含物品个数和体积,也没必要多想,可以直接记住!

2、状态转移方程

根据最后一步的状况,分情况讨论。

这里的dp[i][j]分为两种情况:

  1. 不选i物品:dp[i-1][j]:此时状态表示就是第i-1个物品状态,直接照抄即可
  2. 选i物品:dp[i-1][j-v[i]]+w[i]:因为我们已经挑选了第i个物品,因此第i个物品的价值一定是先加上的。在我们选了第i个物品的情况下,我们就需要找在前i-1个物品中体积等于j-v[i]的状态。当然这里的前提是必须 j-v[i] 要大于等于0,从坐标要大于等于0 也可以看出!

综上,状态转移方程就是求这两者的最大值。

3、初始化

根据经验,我们必须多一层空间,防止下标越界。

根据转移方程,我们我们发现对于列是不会产生越界的,因为我们对于列下标都会有j-v[i] >= 0判断!

所以我们只需要考虑行初始化,下面的背包问题也是如此,列的下标越界问题不用考虑!只需要考虑行的初始化。

在第0行,表示在前0个物品中,总体积为j所表示的总价值,不存在,所以可以直接初始化为0。

4、填表顺序

根据状态转移方程可知,由上到下,由左到右。

5、返回值

由题意中的求这个背包至多能装多大价值的物品,所以我们返回dp[n][V].

n表示一共有n个物品,V表示背包所能容纳的最大体积。


我们继续解决第二问,背包必须装满的情况下。

1、状态表示

dp[i][j] 此时状态表示要与第一问进行区分:

dp[i][j] 表示从前i个物品中挑选,总体积正好等于j,所有选法中能挑选出的最大价值

2、状态转移方程

大部分内容与第一问相同,但是我们要考虑在前i个物品中挑选,可能体积要求不满足,也就是条件不存在的情况!

因此我们需要将不成立的部分要特殊处理!!!目的都是为了不要使用这些不存在的值

第一种,将不存在的情况赋值成-1.

第二种,将这些值赋值成0x3f3f3f3f,表示最大值,或者负的,表示最小值。

3、初始化
还是跟之前一样,第一列不需要初始化。

第一行的第一个数存在,赋值为0。但是后面的值就不存在,在前0个物品中,挑选出体积正好为1、2、3……这些情况都不存在,所以赋值为-1

4、填表顺序

从上往下

5、返回值

dp[n][V]


空间优化:

1、利用滚动数组在空间上的优化

我们可以直接用一维dp数组去代替二维数组

2、直接在原始的代码上稍加修改即可

直接将横坐标删除,然后遍历顺序修改成从右往左

为何遍历顺序改成从右往左?因为我们在初始化dp表时,用到了左上角的值,而一维滚动初始化时从左往右会导致新一轮的值会被覆盖、修改掉。因此需要从右往左进行初始化dp表!

空间优化后的代码

#include <iostream>
#include<bits/stdc++.h>
using namespace std;int dp[1010];
int v[1010];
int w[1010];int main()
{int n = 0, V = 0;cin >> n >> V;for(int i = 1; i <= n; i++){cin >> v[i] >> w[i];}//解决第一问for(int i = 1; i <= n; i++){for(int j = V; j >= v[i]; j--){dp[j] = max(dp[j], w[i]+dp[j-v[i]]);}}cout << dp[V] << endl;//解决第二问memset(dp,0,sizeof(dp));for(int i = 1; i <= V; i++) dp[i] = -1;for(int i = 1; i <= n; i++){for(int j = V; j >= 1; j--){if(j >= v[i] && dp[j-v[i]] != -1){dp[j] = max(dp[j], w[i]+dp[j-v[i]]);}}}if(dp[V] == -1)  cout << 0;else    cout << dp[V];return 0;  
}

二、完全背包

【模板】完全背包_牛客题霸_牛客网 (nowcoder.com)

我们先解决第一问,背包没有装满的情况下。

1、状态表示:

跟01背包状态表示一致。

dp[i][j] 表示从前i个物品中挑选,总体积不超过j,所有选法中能挑选出的最大价值。

2、状态转移方程

01背包和完全背包的本质区别就是能选择数量不一样,01背包数量只有1个,而完全背包可选择物品数量有无限多个

因此状态转移方程根据可选择物品数量分为很多种。

那有无限多种,如何将其转化为只有一种状态或者两种状态呢?

根据数学知识将纵坐标j 进行代换变成 j-v[i],进行如下证明即可得:

最终的方程就是:

dp[j] = max(dp[j], dp[j-v[i]] + w[i]);

这里可以直接记忆最后的答案,证明过程了解。

简记就是将第一个状态转移表达式中的横坐标加1即可!

3、初始化

只需要初始化第一行初始化为0即可

4、填表顺序

根据状态转移方程,从上往下填写每一行,每一行从左往右

5、返回值

dp[n][V]


我们继续解决第二问,背包必须装满的情况下。

1、状态表示

dp[i][j] 此时状态表示要与第一问进行区分:

dp[i][j] 表示从前i个物品中挑选,总体积正好等于j,所有选法中能挑选出的最大价值

2、状态转移方程

与第一问的区别就是:需要用-1额外表示不存在的状态。

3、初始化

将不存在的情况赋值为-1。

第一行除了第一个位置其余都不存在。

4、填表顺序

同第一问

5、返回值

同第一问

空间优化:

同样也是利用滚动数组进行空间优化。

注意这里与01背包的区别就是从左往右遍历。

区分:

01背包从右往左遍历的原因是他运用到了上一行的值,因为是横坐标是 i-1

而完全背包的状态转移方程的横坐标是

这两者状态转移方程的区别也决定了他们在初始化方向的问题!!!

虚线表示01背包的方向,实现表示完全背包的方向。

最终优化后的代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;int v[1010];
int w[1010];int dp[1010];int main()
{  int n = 0, V = 0;cin >> n >> V;for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];//vector<vector<int>> dp(n+1, vector<int>(V+1));//解决第一问for(int i = 1; i <= n ; i++){//从左往右遍历for(int j = 1; j <= V ; j++){if(j-v[i] >= 0){dp[j] = max(dp[j], dp[j-v[i]] + w[i]);}}}cout << dp[V] << endl;//解决第二问memset(dp,0,sizeof(dp));//先初始化为-1for(int i = 1; i <= V; i++) dp[i] = -1;for(int i = 1; i <= n ; i++){for(int j = 1; j <= V ; j++){if(j-v[i] >= 0 && dp[j-v[i]] != -1){dp[j] = max(dp[j], dp[j-v[i]] + w[i]);}}}if(dp[V] == -1) cout << 0;else cout << dp[V];return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/12695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

干货教程【AI篇】| Topaz Video Enhance AI超好用的视频变清晰变流畅的AI工具,免费本地使用

关注文章底部公众号&#xff0c;回复关键词【tvea】即可获取Topaz Video Enhance AI。 一款非常好用的视频变清晰变流畅的AI工具&#xff0c;即提高视频的分辨率和FPS&#xff0c;亲测效果非常nice&#xff01;&#xff01; 免费&#xff01;免费&#xff01;免费&#xff01…

【案例】使用Vue实现标题项元素上下移动

效果图 效果说明 每一组数据只能在对应的二级类目中进行上下移动&#xff0c;当点击上移图标的时候【左边的】会将当前元素与上一个元素交换位置&#xff0c;当点击的元素为该组的第一个元素时&#xff0c;将提示已经是第一项了并且不能进行移动&#xff1b;当点击下移图标的时…

Linux|如何允许 awk 使用 Shell 变量

引言 当我们编写 shell 脚本时&#xff0c;我们通常会在脚本中包含其他较小的程序或命令&#xff0c;例如 awk 操作。就 Awk 而言&#xff0c;我们必须找到将一些值从 shell 传递到 Awk 操作的方法。 这可以通过在 Awk 命令中使用 shell 变量来完成&#xff0c;在本文中&#x…

C++系统编程篇——Linux初识(系统安装、权限管理,权限设置)

(1)linux系统的安装 双系统---不推荐虚拟机centos镜像&#xff08;可以使用&#xff09;云服务器/轻量级云服务器&#xff08;强烈推荐&#xff09; ①云服务器&#xff08;用xshell连接&#xff09; ssh root公网IP 然后输入password ①添加用户&#xff1a; addus…

揭秘!你的电商产品为何滞销?同行火爆销售的7大原因!

同样做电商&#xff0c;但自家产品销量不如竞对同行&#xff0c;可能的原因有多种&#xff0c;以下是店雷达总结7个可能的原因和对策&#xff1a; 一、市场竞争分析不足 未能准确识别并分析竞争对手的产品、定价、营销策略等关键信息&#xff0c;导致自身产品无法脱颖而出。 …

机器学习(四) ----------逻辑回归

目录 1 概述 2 极大似然估计 3 逻辑回归核心思想 3.1 对数似然损失&#xff08;Log-likelihood Loss&#xff09; 4 分类问题的评估方法 4.1 混淆矩阵&#xff08;Confusion Matrix&#xff09;&#xff1a; 4.2 准确率&#xff08;Accuracy&#xff09; 4.3 精确率&am…

数据结构与算法学习笔记三---栈和队列

目录 前言 一、栈 1.栈的表示和实现 1.栈的顺序存储表示和实现 1.C语言实现 2.C实现 2.栈的链式存储表示和实现 1.C语言实现 2.C实现 2.栈的应用 1.数制转换 二、队列 1.栈队列的表示和实现 1.顺序队列的表示和实现 2.链队列的表示和实现 2.循环队列 前言 这篇文…

P9748 [CSP-J 2023] 小苹果:做题笔记

目录 P9748 [CSP-J 2023] 小苹果 思路 代码 P9748 [CSP-J 2023] 小苹果 P9748 [CSP-J 2023] 小苹果 思路 先写几个看看规律 题意我们能看出来是三个三个一组的&#xff0c;然后每次取走的都是三个里面的第一个。我们应该很容易想到如果一轮的总数是三的倍数的话&#xff0…

94、动态规划-最长公共子序列

递归的基本思路&#xff1a; 比较两个字符串的最后一个字符。如果相同&#xff0c;则这个字符一定属于最长公共子序列&#xff0c;然后在剩余的字符串上递归求解。如果最后一个字符不相同&#xff0c;则分两种情况递归求解&#xff1a; 去掉 text1 的最后一个字符&#xff0c;保…

【论文笔记 | 异步联邦】FedSA

FedSA&#xff1a;一种处理 non-IID 数据 的 过时感知 异步联邦算法 1. 论文信息 FedSA&#xff1a;A staleness-aware asynchronous Federated Learning algorithm with non-IID data&#xff0c;Future Generation Computer Systems&#xff0c;2021.7&#xff0c;ccfc 是…

RHEL之网络接口的绑定

前言 这些步骤最好都在虚拟机中完成 网络接口绑定是将多个网络接口逻辑地连接在一起&#xff0c;目的一是避免网络接口的单点故障&#xff0c;二是提高带宽以提高吞吐率 具体步骤 1.用ip link查看有哪些网络接口 2.添加一个类型bond的连接 nmcli con add type bond con-nam…

【汇编】算术指令

一、加法指令 &#xff08;一&#xff09;各加法指令的格式及操作 加法指令可做字或字节运算 &#xff08;1&#xff09;加法指令 ADD 格式&#xff1a;ADD DST,SRC执行的操作&#xff1a;(DST) ← (SRC)(DST) &#xff08;2&#xff09;带进位加法指令 ADC 格式&#xf…

AIGC岗位需求增长超300%,平均年薪超40万元

AI圈最近又发生了啥&#xff1f; AIGC 应用爆发&#xff0c;相关岗位需求增长超 300%、平均招聘年薪超 40 万元 随着 AI应用的爆发&#xff0c;生成式人工智能(AIGC)的招聘市场十分火爆。数据显示今年一季度&#xff0c;生成式人工智能相关职位需求同比增长超三倍。从全平台增…

功能安全如何在公司顺利开展?-亚远景科技

亚远景功能安全主题线上会议报名开启&#xff01; 随着汽车技术的不断发展&#xff0c;汽车系统的复杂性和交互性大幅增加&#xff0c;功能安全成为确保驾驶员、乘客及行人安全的关键。 本场功能安全线上会议&#xff0c;亚远景为汽车行业的相关人员准备了以下内容&#xff1a…

Linux|基础IO

Linux|基础IO 回顾c语言的文件操作提炼对文件的理解系统调用初始open函数返回值fd为什么我们向fd一个整数写就写入文件了呢&#xff1f;怎么理解读写操作总结open函数有哪些功能怎么理解往硬件&#xff08;显示器&#xff0c;键盘&#xff09;中读写数据如何理解FILE*访问文件 …

【C语言】自定义类型之---结构体超详解(结构体的定义使用、指针结构体,内存对齐,......代码详解)

目录 前言&#xff1a; 一&#xff1a;结构体 1.1&#xff1a;什么是结构体&#xff1f; 1.2&#xff1a;结构体类型的声明 1.3&#xff1a;结构体变量的定义 1.4&#xff1a;结构体的内存对齐 1.5&#xff1a;结构体传参 二&#xff1a;位段 2.1&#xff1a;位段是什…

2024年【金属非金属矿山(露天矿山)安全管理人员】模拟考试题库及金属非金属矿山(露天矿山)安全管理人员作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 金属非金属矿山&#xff08;露天矿山&#xff09;安全管理人员模拟考试题库参考答案及金属非金属矿山&#xff08;露天矿山&#xff09;安全管理人员考试试题解析是安全生产模拟考试一点通题库老师及金属非金属矿山&a…

Google I/O 2024 干货全解读:Gemini AI 横空出世,智能未来触手可及!

Google I/O 2024 干货全解读&#xff1a;Gemini AI 横空出世&#xff0c;智能未来触手可及&#xff01; 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》…

面试前端随笔20240510

最近公司招聘前端开发人员有幸参与帮听&#xff0c;总结了三个有关vue的面试问题和答案&#xff0c;现在分享一下。 1.Vue2数据监听无法监听数组为啥&#xff1f;有啥解决方案&#xff1f;vue3中是如何处理这个问题&#xff1f; vue2的官方说明了defineProperty的一些限制&…

Oracle SQL Developer 脚本输出中文显示乱码

问题描述 在测试Oracle Select AI&#xff08;自然语言查询数据库&#xff09;时&#xff0c;发现Run Statement中文显示正常&#xff1a; 而Run Script中文显示乱码&#xff1a; 问题解决 进入菜单Tools>Preferences...>Environment&#xff0c; 修改SQL Developer…