浅说背包问题(上)

news2024/9/19 10:58:12

背包问题

  • 什么是背包问题
  • 背包的分类
  • 01背包
    • 思路一
    • 思路二
    • 思路三(重头戏)
      • 常规代码
      • 空间优化
  • 例题讲解
    • [NOIP2001 普及组] 装箱问题
      • 题目描述
      • 输入格式
      • 输出格式
      • 样例 #1
        • 样例输入 #1
        • 样例输出 #1
      • 提示
      • 思路
    • 最大约数和
      • 题目描述
      • 输入格式
      • 输出格式
      • 样例 #1
        • 样例输入 #1
        • 样例输出 #1
      • 提示
      • 思路

什么是背包问题

背包问题是线性DP的一个拓展,它的模型一般为:
有一个体积为V的背包,有n种物品,每种物品的数量有限或者无限,每个物体有它的属性(体积、质量等),问在不超过背包体积的情况下如何选择物品才能让物品的属性之和最大。

首先,很容易想到贪心是错误的,无论是从大到小贪,还是从小到大贪心的往背包里放物品,都可以找到反例。那么我们在这个地方就要考虑动态规划了

背包的分类

背包的类型有很多,比如最简单的01背包,还有稍微复杂一点的多重背包和完全背包以及混合背包,除此之外,还有更难的泛化背包,多维背包,组合背包等,本文先讲解最简单的01背包,至于其余的背包,其实都是从01背包去进行更改的

01背包

有N件物品和一个容量为V的背包。第i件物品的体积是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。

01背包特点:每种物品有且仅有一件,并且不可以再分。该物品要么取走,要么不取,只有两种状态,所以叫01背包。同时,01背包也是所有背包模型的基础。

思路一

每一种物品有两种状态(0和1),判断所有组成的方案,然后找出其中价值最大的。时间复杂度O(2^n).理论上是不可能实现的。

思路二

回溯法。时间复杂度和上面差不多。

思路三(重头戏)

动态规划
每种物品只有两种状态(0和1)。要求背包的最大价值。设前i件物品(部分/全部)放入体积为v的背包中的最大价值是 f [ i ] [ v ] f[i][v] f[i][v]

取走: f [ i ] [ v ] = f [ i − 1 ] [ v − c [ i ] ] + w [ i ] ; f[i][v]=f[i-1][v-c[i]]+w[i]; f[i][v]=f[i1][vc[i]]+w[i];
如果要把第i件物品放入背包中,说明背包中肯定空余第i件物品体积的位置。说明前(i-1)件物品占的体积为v-c[i],那么最大价值就是f[i-1][v-c[i]].既然把第i件物品放进去了,最大价值就+w[i].
不取: f [ i ] [ v ] = f [ i − 1 ] [ v ] ; f[i][v]=f[i-1][v]; f[i][v]=f[i1][v];
如果第i件物品不放入背包中,说明第i件物品是否存在对结果没有影响。前i-1件物品占用的最大体积就是v。最大价值就是f[i-1][v].
所以我们就可以得出这个状态转移方程: f [ i ] [ v ] = m a x ( f [ i − 1 ] [ v − c [ i ] ] + w [ i ] , f [ i − 1 ] [ v ] ) ; f[i][v]=max(f[i-1][v-c[i]]+w[i],f[i-1][v]); f[i][v]=max(f[i1][vc[i]]+w[i],f[i1][v]);
有了状态转移方程,那么我们就可以得出以下代码

常规代码

for(int i=1;i<=n;i++){//枚举所有物品
	for(int v=V,v>0,v--){//枚举范围内所有体积
		if(c[i]<=v){//如果该物品可以放进去
			f[i][v]=max(f[i-1][v-c[i]]+w[i],f[i-1][v]);
		}else f[i][v]=f[i-1][v];//如果该物品肯定放不进去
 	}
}

对于前i件物品,他的状态都是通过前i-1件物品转移过来的,所以v的范围无论是[0,V]还是[V,0]都没有任何关系。初始状态i=0的时候f[0][v]的值就是0,同样的,当v=0的时候,f[i][0]的值也仍然为0.所以不需要额外的初始化。

我们要求的n件物品放入V的背包中的最大价值就是f[N][V]的值

空间优化

不难想到,如果N的值比较大的话,很容易爆空间,那么我们就要想办法进行优化,可以发现,我们的这个状态转移方程只和 v − c [ i ] v-c[i] vc[i]有关,那么我们就可以使用滚动数组进行优化
但是这里要注意,如果我们采用自滚的话,在枚举v的时候就必须从大往小去枚举,因为我们可以发现在计算dp[j]的答案时,会用到dp[j-v[i]]的答案,如果j是正着枚举,dp[j-v[i]]的答案就是已经更新过的,答案是错误的;但是如果我们把j倒着枚举,dp[j]会比dp[j-v[i]]先更新,那么用到的dp[j-v[i]]的值就是上一层的,也就是我们需要的答案。所以01背包如果用一维数组表示,背包体积j的枚举只能倒着枚举,否则答案就是错误的。

for(int i=1;i<=n;i++){
	for(int j=m;j>=v[i];j--){
		dp[j]=max(dp[j-v[i]]+w[i],dp[j]);
	}
}

例题讲解

[NOIP2001 普及组] 装箱问题

题目描述

有一个箱子容量为 V V V,同时有 n n n 个物品,每个物品有一个体积。

现在从 n n n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。

输入格式

第一行共一个整数 V V V,表示箱子容量。

第二行共一个整数 n n n,表示物品总数。

接下来 n n n 行,每行有一个正整数,表示第 i i i 个物品的体积。

输出格式

  • 共一行一个整数,表示箱子最小剩余空间。

样例 #1

样例输入 #1
24
6
8
3
12
7
9
7
样例输出 #1
0

提示

对于 100 % 100\% 100% 数据,满足 0 < n ≤ 30 0<n \le 30 0<n30 1 ≤ V ≤ 20000 1 \le V \le 20000 1V20000

【题目来源】

NOIP 2001 普及组第四题

思路

这道题其实就是一道裸的01背包问题,可以直接解决

#include<bits/stdc++.h>
using namespace std;

int v[20100],dp[20100];
int main(){
	int V,n;
	cin>>V>>n;
	for (int i=1;i<=n;i++){
		cin>>v[i];
	}
	for (int i=1;i<=n;i++){
		for (int j=V;j>=v[i];j--){
			dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
		}
	}
	cout<<V-dp[V];
	return 0;
}

最大约数和

题目描述

选取和不超过 S S S 的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大。

输入格式

输入一个正整数 S S S

输出格式

输出最大的约数之和。

样例 #1

样例输入 #1
11
样例输出 #1
9

提示

【样例说明】

取数字 4 4 4 6 6 6,可以得到最大值 ( 1 + 2 ) + ( 1 + 2 + 3 ) = 9 (1+2)+(1+2+3)=9 (1+2)+(1+2+3)=9

【数据规模】

对于 100 % 100 \% 100% 的数据, 1 ≤ S ≤ 1000 1 \le S \le 1000 1S1000

思路

这题很容易想到搜索,预处理出来每一个数的约数的数量,然后爆搜,但是数据范围很大。既然每一个数字都有两种状态,选或者不选,而且任意两个数字之间也没联系,所以可以直接考虑背包,题目中说了不同的正整数,所以就是一个裸的01背包。先预处理出来[1,n]中每个数的约数的数量,再以n作为背包体积,数字1—n作为体积,约数之和作为价值跑一遍01背包即可。

#include<bits/stdc++.h>
using namespace std;

int a[5100],dp[5100];
void yueshu(int k){
	for (int i=1;i<k;i++){
		if (k%i==0)a[k]+=i;
	}
	return;
}
int main(){
	int s;
	cin>>s;
	for (int i=1;i<=s;i++){
		yueshu(i);
	}
	for (int i=1;i<=s;i++){
		for (int j=s;j>=i;j--){
			dp[j]=max(dp[j],dp[j-i]+a[i]);
		}
	}
	cout<<dp[s];
	return 0;
}

请添加图片描述
请添加图片描述
请添加图片描述

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

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

相关文章

商品分类左右联动

1、先看效果 2、以hooks方法处理&#xff0c;方便复制使用&#xff0c;见代码 Good.vue文件 <script setup lang"ts" name"goods">import {onMounted, ref, nextTick} from "vue";import useProductScroll from "/utils/hooks/useP…

halcon序列化机制

可以结合halcon算子的.net程序进行面向对象的编程&#xff1a; 源码如下&#xff1a; 打开算子的.net程序&#xff1a; 将程序运用到C#中&#xff1a; halcondonet.dll源码解读 halcon与C#联合编程的demo halcon的序列化机制 采用二进制进行序列化保存和反序列化 步骤&#…

GigE Vision GVCP/GVSP

GIGE协议&#xff0c;全称Gigabit Ethernet Vision协议&#xff0c;是一种基于千兆以太网&#xff08;Gigabit Ethernet&#xff09;技术开发的相机接口标准&#xff0c;主要用于高速图像采集和处理。该协议通过以太网技术实现图像数据和控制信号的传输&#xff0c;具有低成本、…

【Conda】命令大全 + 包安装报错一招解决

conda常用命令总结 一、conda常用命令大全 命令用法命令获取版本号conda -V conda --version获取帮助conda -h conda --help获取环境相关命令的帮助conda env -h所有 --单词 都可以用 -单词首字母来代替比如 -version 可以用 -V来代替&#xff0c;只不过有的是大写…

float、double

按照这个规定&#xff0c;单精度浮点数&#xff08;float&#xff09;这个数据类型所占内存大小为4个字节&#xff0c;也就是32位&#xff0c;所以单精度浮点数也叫32位浮点数&#xff0c;它在内存或硬盘中要占用32个比特。 单精度浮点数的尾数部分用23位存储&#xff0c;加上默…

贝叶斯估计模型及 Stata 具体操作步骤

目录 一、引言 二、贝叶斯估计的理论原理 三、Stata 代码示例 四、结果解读与分析 一、引言 贝叶斯估计作为一种强大的统计推断方法&#xff0c;在结合先验信息和样本数据以获得更准确的参数估计方面具有显著优势。本文将深入探讨贝叶斯估计的理论原理&#xff0c;并通过 St…

汇聚荣做拼多多电商怎么样?

汇聚荣做拼多多电商怎么样?在当前电商平台竞争激烈的背景下&#xff0c;拼多多凭借其独特的商业模式和市场定位迅速崛起。对于想要加入拼多多的商家而言&#xff0c;了解平台的特点、优势及挑战是至关重要的。本文将深入分析加入拼多多电商的多个方面&#xff0c;帮助读者全面…

网站外链还有没有作用

前言 还记得“内容为王&#xff0c;外链为皇”这句话吗&#xff1f;在以前网站外链是网站优化中非常主要的环节。那时候做一个网站&#xff0c;只要不停的发外链&#xff0c;收录就不会差&#xff0c;于是大部分站长都使劲发外链。 有市场就有商场&#xff0c;大家都看到外链…

昇思25天学习打卡营第18天|MindNLP ChatGLM-6B StreamChat

MindNLP ChatGLM-6B StreamChat MindNLP ChatGLM-6B StreamChat是基于MindNLP框架和ChatGLM-6B模型实现的聊天应用&#xff0c;利用自然语言处理技术&#xff0c;实现与用户的自然语言交流。这样的应用可以广泛应用于智能客服、在线助理和社交聊天等场景。 在当前技术环境下&a…

大数据------JavaWeb------VueElement(完整知识点汇总)

Vue 定义 Vue是一套前端框架&#xff0c;可以免除原生JavaScript中的DOM操作&#xff0c;简化书写 之前所学的MyBatis框架是用来简化JDBC代码编写的&#xff1b;而Vue是前端框架&#xff0c;用来简化JavaScript代码编写的 在Axios与JSON综合案例的添加中有大量的DOM操作&#…

设备运维、教学直播...浅析远程控制在医疗专网环境下的应用

在医疗行业内&#xff0c;无论是高端的医疗设备&#xff0c;还是医疗机构使用的各种数字化系统&#xff0c;出于安全考虑往往都搭建在专网内网之中&#xff0c;无法直接与外网连接。在这种情况下&#xff0c;常规的远程控制变得很难接入到医疗业务中。 但另一方面&#xff0c;…

TP5 封装通用的微信服务类

1、安装依赖包 我们这里用的是 EasyWeChat EasyWeCha官网 https://www.easywechat.com/ 安装地址 https://github.com/easywechat/docs 相关文档 https://www.easywechat.com/docs/4.1/payment/index composer安装 $ composer require overtrue/wechat:~4.0 -vvv1、封装服务类 …

matlab R2016b安装cplex12.6,测试时cplex出现出现内部错误的解决方法

问题场景 网上搜索matlabyalmipcplex的安装教程&#xff0c;跟着步骤操作即可&#xff0c;假如都安装好了&#xff0c;在matlab中测试安装是否成功&#xff0c;出现以下问题&#xff1a; 1、matlab中设置路径中添加了yalmip和cplex路径&#xff0c;在命令窗口中输入yalmiptest…

[Flask笔记]一个完整的Flask程序

前面讲过Flask是一个轻量级Web开发框架&#xff0c;为什么说是轻量级的呢&#xff0c;因为它用短短几行代码就能运行起来&#xff0c;我们一起来看看最简单的flask框架。 安装Flask 在看Flask框架之前我们需要先安装flask模块&#xff0c;学过python的肯定都知道&#xff0c;…

python3读取shp数据

目录 1 介绍 1 介绍 需要tmp.shp文件和tmp.dbf文件&#xff0c;需要安装geopandas第三方库&#xff0c;python3代码如下&#xff0c; import geopandas as gpdshp_file_path "tmp.shp" shp_data gpd.read_file(shp_file_path) for index, row in shp_data.iterro…

久期分析与久期模型

目录 一、久期分析的理论原理 二、数据准备 三、Stata 程序代码及解释 四、代码运行结果 一、久期分析的理论原理 久期&#xff08;Duration&#xff09;是衡量债券价格对利率变动敏感性的重要指标。它不仅仅是一个简单的时间概念&#xff0c;更是反映了债券现金流回收的平均…

最新 Kubernetes 集群部署 + Contranerd容器运行时 + flannel 网络插件(保姆级教程,最新 K8S 1.28.2 版本)

资源列表 操作系统配置主机名IP所需插件CentOS 7.92C4Gk8s-master192.168.60.143flannel-cni-plugin、flannel、coredns、etcd、kube-apiserver、kube-controller-manager、kube-proxy、 kube-scheduler 、containerd、pause 、crictlCentOS 7.92C4Gk8s-node01192.168.60.144f…

BGP第三日谈

今日所用拓扑 先补充昨日没有讲到的知识点&#xff1a; 1.IBGP有更新源检测机制 这种机制使得BGP路由在IBGP邻居间传递时下一跳地址仍然保持不变&#xff0c;但是IBGP却没有去往下一跳地址的路由&#xff0c;所以我们需要手动将IBGP邻居间传递的BGP路由下一跳地址转成与IBGP…

星辰考古:TiDB v4.0 进化前夜

前情回顾TiDB v4 时间线TiDB v4 新特性 TiDBTiKVPDTiFlashTiCDCTiDB v4 兼容性变化 TiDBTiKVPD其他TiDB 社区互助升级活动TiDB 3.0.20 升级到 4.0.16 注意事项升级速览直观变化总结素材来源&#x1f33b; 往期精彩 ▼ 前情回顾 在前面的章节中&#xff0c;我们共同梳理了 TiDB …

【ARM】CCI缓存一致性整理

目录 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置​编辑 3.CCI500内部结构​编辑 4.功能描述 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置 3.CCI500内部结构 Transaction Tracker&#xff08;TT&#xff09;是用来解决一致性和ordering问题的&#xff0c;它…