数据结构与算法学习笔记(Acwing提高课)----动态规划·背包模型(一)

数据结构与算法学习笔记----动态规划·背包模型(一)

@@ author: 明月清了个风
@@ first publish time: 2025.5.1

ps⭐️背包模型是动态规划中的重要模型,基础课中已对背包模型的几种模版题有了讲解,[链接在这](数据结构与算法学习笔记----背包问题_有 n 件物品和一个体积为 m 的背包。第 i 个物品的体积为 vi,价值为 wi。每件物品-CSDN博客),

⭐️题目非常多,计划大概写两到三篇,建议首先复习一下基础课中对应的背包模型。这次是按照题目顺序写的,没有按照视频讲的顺序,因为刚开始讲的就是一系列多重背包问题,相对比较难,因此没有按照这个顺序。并且按照对应的背包模型进行了题目的分类,没有完全按照原来的顺序。

这一篇中主要是01背包问题和二维背包问题的应用题。

很多题目的代码都可以进行优化,有些题目给出了优化前后的代码,有些比较简单直接给了优化后的如二维背包问题的优化,建议可以先尝试写无优化的再看优化后的代码。

Acwing 423. 采药

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。

为此,他想拜附近最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。

医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

输入文件的第一行有两个整数 T T T M M M,用一个空格隔开, T T T代表总共能够用来采药的事件, M M M代表山洞里的草药的数目。

接下来的 M M M行每行包括两个在 1 1 1 100 100 100之间的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出文件包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

数据范围

1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000

0 ≤ M ≤ 100 0 \le M \le 100 0M100

思路

这一题就是01背包问题的包装版本,思路完全一致,只是加入了具体场景的引用,算是本节内容的入门题了,就不具体讲了。可以用来复习01背包,下面给出了两个版本的代码,对应了无优化和有优化的版本,主要是对存储空间进行了优化,优化方法在基础课中已经详细讲过,这里就不讲了,那篇[链接在这](数据结构与算法学习笔记----背包问题_有 n 件物品和一个体积为 m 的背包。第 i 个物品的体积为 vi,价值为 wi。每件物品-CSDN博客)。

代码-无优化

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 110, M = 1010;int n, m;
int v[N], w[N];
int f[N][M];int main()
{cin >> m >> n;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 ++){f[i][j] = f[i - 1][j];if(j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);}}cout << f[n][m] << endl;return 0;
}

代码-有优化

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 110, M = 1010;int n, m;
int v[N], w[N];
int f[M];int main()
{cin >> m >> n;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 --)f[j] = max(f[j], f[j - v[i]] + w[i]);}cout << f[m] << endl;return 0;
}

Acwing 1024. 装箱问题

有一个箱子容量 V V V,同时有 n n n个物品,每个物品有一个体积(正整数)。

要求 n n n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入格式

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

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

接下来 n n n行,每行一个正整数,分别表示这 n n n个物品的各自体积。

输出格式

一个整数,表示箱子剩余空间。

数据范围

1 ≤ V ≤ 20000 1 \le V \le 20000 1V20000

0 ≤ n ≤ 30 0 \le n \le 30 0n30

思路

这一题也是基本的01背包问题,为使剩余空间最小,就要拿体积做大的组合,虽然没有物品价值,但是可以将物品价值看成与该物品体积相同,这样就能转化为最基本的01背包问题了。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 20010;int f[N];
int m, n;int main()
{cin >> m >> n;for(int i = 0; i < n; i ++){int v;cin >> v;for(int j = m; j >= v; j --) f[j] = max(f[j], f[j -v] + v);}cout << m - f[m] << endl;return 0;
}

Acwing 278. 数字组合

给定 N N N个正整数 A 1 , A 2 , ⋯ , A N A_1,A_2,\cdots,A_N A1,A2,,AN,从中选出若干个数,使它们的和为 M M M,求有多少种方案。

输入格式

第一行包含两个整数 N N N M M M

第二行包含 N N N个整数,表示 A 1 , A 2 , ⋯ , A N A_1,A_2,\cdots,A_N A1,A2,,AN

输出格式

包含一个整数,表示可选方案数。

数据范围

1 ≤ N < 100 1 \le N < 100 1N<100

1 ≤ M < 10000 1 \le M < 10000 1M<10000

1 ≤ A i ≤ 1000 1 \le A_i \le 1000 1Ai1000

思路

同样是01背包的一个应用题,将所有数看成物品,数值看做体积即可,只不过要求的是体积正好为 M M M的方案数,对于状态表示使用f[i][j]表示从前 i i i个数中选,且和为 j j j的方案,属性是方案数。

对于状态转移,根据第 i i i个数的选择情况即可。

需要注意的是,因为要求的是方案数,因此需要对f[0]进行初始化。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 10010;int n, m;
int f[N];int main()
{cin >> n >> m;f[0] = 1;for(int i = 1; i <= n; i ++){int v;cin >> v;for(int j = m; j >= v; j --) f[j] += f[j - v];}cout << f[m] << endl;return 0;
}

Acwing 8. 二维费用的背包问题

N N N件物品和一个容量为 V V V的背包,背包能承受的最大重量是 M M M

每件物品只能用一次。体积是 v i v_i vi,重量是 m i m_i mi,价值是 w i w_i wi

求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大。
输出最大价值。

输入格式

第一行三个整数, N , V , M N,V,M N,V,M,用空格隔开,分别表示物品件数、背包容积和背包可承受的最大重量。

接下来 N N N行,每行三个整数 v i , m i , w i v_i,m_i,w_i vi,mi,wi,用空格隔开,分别表示第 i i i件物品的体积,重量和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N < 1000 0 < N < 1000 0<N<1000

0 < V , M < 100 0 < V,M < 100 0<V,M<100

0 < v i , m i < 100 0 < v_i,m_i < 100 0<vi,mi<100

0 < w i ≤ 1000 0 < w_i \le 1000 0<wi1000

思路

对于二维费用来说,仅仅是对一维01背包的扩展,在难度上其实并没有太大的提升,因为多了一维限制,因此状态表示也变成了三维,使用f[i][j][k]表示所有从前 i i i个物品中选,并且总体积不超过 j j j,总重量不超过 k k k的选法。

对于状态划分,同样根据最后一个物品的选择进行划分,分为选物品 i i i和不选物品 i i i的两个部分,代码很简单,同样可以和01背包一样进行空间优化,这里直接给出了优化版本的代码,可以先尝试写无优化的版本再看这个。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 1010;int n, V1, V2;
int f[N][N];int main()
{cin >> n >> V1 >> V2;for(int i = 1; i <= n; i ++){int v1,v2,w;cin >> v1 >> v2 >> w;for(int j = V1; j >= v1; j --)for(int k = V2; k >= v2; k --)f[j][k] = max(f[j][k], f[j - v1][k - v2] + w);}cout << f[V1][V2] << endl;return 0;
}

Acwing 1022. 宠物小精灵之收服

宠物小精灵是一部讲述小智和他的搭档皮卡丘一起冒险的故事。

一天,小智和皮卡丘来到了小精灵狩猎场,里面有很多珍贵的野生宠物小精灵。

小智也想收服其中的一些小精灵。然而,野生的小精灵并不那么容易被收服。

对于每一个野生小精灵而言,小智可能需要使用很多个精灵球才能收服它,而在收服过程中,野生小精灵也会对皮卡丘造成一定的伤害(从而减少皮卡丘的体力)。

当皮卡丘的体力小于等于0时,小智就必须结束狩猎(因为他需要给皮卡丘疗伤),而使得皮卡丘体力小于等于0的野生小精灵也不会被小智收服。当小智的精灵球用完时,狩猎也宣告结束。

我们假设小智遇到野生小精灵时有两个选择:收服它,或者离开它。如果小智选择了收服,那么一定会扔出能够收服该小精灵的精灵球,而皮卡丘也一定会受到相应的伤害;如果选择离开它,那么小智不会损失精灵球,皮卡丘也不会损失体力。

小智的目标有两个:主要目标是收服尽可能多的野生小精灵;如果可以收服的小精灵数量一样,小智希望皮卡丘受到的伤害越小(剩余体力越大),因为他们还要继续冒险。

现在已知小智的精灵球数量和皮卡丘的初始体力,已知每一个小精灵需要的用于收服的精灵球数目和它在被收服过程中会对皮卡丘造成的伤害数目。请问,小智该如何选择收服哪些小精灵以达到他的目标呢?

输入格式

输入数据的第一行包含三个整数: N N N M M M K K K,分别代表小智的精灵球数量、皮卡丘初始的体力值、野生小精灵的数量。

之后的 K K K行,每一行代表一个野生小精灵,包括两个整数:收服该小精灵需要的精灵球的数量,以及收服过程中对皮卡丘造成的伤害。

输出格式

输出为一行,包含两个整数 C , R C,R C,R,分别表示最多收服 C C C个小精灵,以及收服 C C C个小精灵时皮卡丘的剩余体力值最多为 R R R

数据范围

0 < N < 1000 0 < N < 1000 0<N<1000

0 < M < 500 0 < M < 500 0<M<500

0 < K < 100 0 < K < 100 0<K<100

思路

根据题意可以发现,一共有两个值有上限,也就是01背包问题中的体积,一个是精灵球的数量,另一个是皮卡丘的体力值,而要求的目标是野生小精灵的数量,因此,这一题为二维背包问题。

对于状态表示而言,使用f[i][j][k]表示所有从前 i i i个物品中选择,且花费不超过 j j j和不超过 k k k的选法,也就是有两个限制,在这一题中就是从前 i i i个小精灵中选择要收服的小精灵,且精灵球数量不能超过 j j j,皮卡丘的体力值不能超过 k k k的方案,属性为最大值。

对于状态转移而言就和一维背包问题是一样的。需要注意的是本题的第二问要皮卡丘的剩余体力值最多,需要找到收服 C C C个小精灵时剩余的最多体力。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 1010, M = 510;int n, m, k;
int f[N][M];int main()
{cin >> n >> m >> k;for(int i = 0; i < k; i ++){int v1, v2;cin >> v1 >> v2;for(int j = n; j >= v1; j --)for(int z = m - 1; z >= v2; z --)f[j][z] = max(f[j][z], f[j - v1][z - v2] + 1);}cout << f[n][m - 1] << endl;int x = m - 1;while(x > 0 && f[n][x - 1] == f[n][m - 1]) x --;cout << m - x << endl;return 0;}

Acwing 1020. 潜水员

潜水员为了潜水要使用特殊的装备。

他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。

潜水员有一定数量的气缸。

每个气缸都有重量和气体容量。

潜水员为了完成他的工作需要特定数量的氧和氮。

他完成工作所需气缸的总重的最低限度的是多少?

例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:

3 36 120
10 25 129
5 50 250
1 45 130
4 20 119

如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。

你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。

输入格式

第一行有 2 2 2个整数 m , n m,n m,n,他们表示氧、氮各自需要的量。

第二行为整数 k k k表示气缸的个数。

此后的 k k k行,每行包括 a i , b i , c i a_i,b_i,c_i ai,bi,ci 3 3 3个整数,这些各自是:第 i i i个气缸里的氧和氮的容量及汽缸重量。

输出格式

仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。

数据范围

1 ≤ m ≤ 21 1 \le m \le 21 1m21

1 ≤ n ≤ 79 1 \le n \le 79 1n79

1 ≤ k ≤ 1000 1 \le k \le 1000 1k1000

1 ≤ a i ≤ 21 1 \le a_i \le 21 1ai21

1 ≤ b i ≤ 79 1 \le b_i \le 79 1bi79

1 ≤ c i ≤ 800 1 \le c_i \le 800 1ci800

思路

首先很容易看出这题有两个限制氧气和氮气,但是与上一题不同的是,对于这两维费用的要求是至少需要这么多,使重量最低,也就是和上面的题目是反过来的,因此也需要有一些变化。

对于背包问题的状态表示而言,体积的限制有三种:①体积最多是 j j j ②体积恰好是 j j j ③体积至少是 j j j。这一题就是第三种情况。

对于状态表示,仍然是使用f[i][j][k],但含义变为所有从前 i i i个气缸中选,并且氧气至少是 j j j,氮气至少是 k k k的选法,要求的属性是最小值。

对于状态划分,仍然是根据第 i i i个气缸的选择进行划分,也就是是否包含该气缸,所有不包含第 i i i个物品的所有选法也就是f[i - 1][j][k],包含第 i i i个物品的选择集合可以先将物品 i i i去掉,那么根据一般的表示就是f[i - 1][j - v1][k - v2],但是需要注意的是,在之前如果是这个式子,因为要求是体积恰好是 j j j k k k,因此我们会有一个判断就是 j ≥ v 1 j \ge v1 jv1 k ≥ v 2 k \ge v2 kv2才能成立,但是在这里因为要求是至少有那么多,只要比它多就是成立的,因此对于 j j j k k k的限制就失效了,即使此时 j < v 1 j < v1 j<v1或者 k < v 2 k < v2 k<v2也可以,因为实际意义是至少要这么多氧气和氮气,因此它最低就是 0 0 0,表示什么都没选,而选择了物品 i i i之后就满足了氧气至少为 j j j,氮气至少为 k k k,也就是只要比 j j j k k k多就行,多多少都没事。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>using namespace std;const int N = 22, M = 80;int n, m, k;
int f[N][M];int main()
{cin >> n >> m >> k;memset(f, 0x3f, sizeof f);f[0][0] = 0;while(k --){int v1, v2, w;cin >> v1 >> v2 >> w;for(int j = n; j >= 0; j --)for(int z = m; z >= 0; z --)f[j][z] = min(f[j][z], f[max(0, j -v1)][max(0, z - v2)] + w);}cout << f[n][m] << endl;return 0;
}

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

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

相关文章

Java关键字解析

Java关键字是编程语言中具有特殊含义的保留字&#xff0c;不能用作标识符&#xff08;如变量名、类名等&#xff09;。Java共有50多个关键字&#xff08;不同版本略有差异&#xff09;&#xff0c;下面我将分类详细介绍这些关键字及其使用方式。 一、数据类型相关关键字 1. 基…

vue自定义表头内容excel表格导出

1、安装 npm install xlsx file-saver 2、使用 import * as XLSX from xlsx import { saveAs } from file-saverconst exportAccounts (data) > {// 将对象数组转换为 worksheetconst worksheet XLSX.utils.json_to_sheet(data)// 创建 workbook 并附加 sheetconst wor…

鸿蒙NEXT开发组件截图和窗口截图工具类SnapshotUtil(ArkTs)

import { image } from kit.ImageKit; import { componentSnapshot, window } from kit.ArkUI; import { AppUtil } from ./AppUtil; import { ArrayUtil } from ./ArrayUtil;/*** 组件截图和窗口截图工具类* author 鸿蒙布道师* since 2025/04/28*/ export class SnapshotUtil…

C#与SVN的深度集成:实现版本控制自动化管理​

目录 1. 环境准备 2. 创建 C# 工程 3. 引用 SharpSvn 库 4. 编写代码 1. 环境准备 2. 创建 C# 工程 3. 引用 SharpSvn 库 4. 编写代码 5. 代码说明 6. 注意事项 1. 环境准备 首先&#xff0c;需要安装 SharpSvn 库。可以从 SharpSvn 官方网站 下载适合 .NET Framewor…

本文不定期更新,用于收录各种怪异的python脚本

1.计算自然数对数底 a b 1 for n in range(1, 1001):a a * n 1b b * n t a % br . for i in range(1, 1001):t 10if t < b:r 0else:r str(t // b)t % bprint(str(a//b) r) 得到 2.7182818284590452353602874713526624977572470936999595749669676277240766303…

日志之ClickHouse部署及替换ELK中的Elasticsearch

文章目录 1 ELK替换1.1 Elasticsearch vs ClickHouse1.2 环境部署1.2.1 zookeeper 集群部署1.2.2 Kafka 集群部署1.2.3 FileBeat 部署1.2.4 clickhouse 部署1.2.4.1 准备步骤1.2.4.2 添加官方存储库1.2.4.3 部署&启动&连接1.2.4.5 基本配置服务1.2.4.6 测试创建数据库和…

2025年大一ACM训练-搜索

2025年大一ACM训练-搜索 前期知识&#xff1a;DFS&#xff0c;本文搜索题解法以深度优先搜索为主 1.1 DFS 的定义 深度优先搜索&#xff08;Depth-First Search&#xff09;是一种用于遍历树或图的算法。核心思想是尽可能“深入”访问图的每个节点&#xff0c;直到无法继续前进…

Nginx核心功能02

目录 一&#xff0c;正向代理 1&#xff0c;编译安装Nginx &#xff08;1&#xff09;安装支持软件 &#xff08;2&#xff09;创建运行用户&#xff0c;组和日志目录 &#xff08;3&#xff09;编译安装Nginx &#xff08;4&#xff09;添加Nginx系统服务 2&#xff0c…

rk3568安全启动功能实践

本文主要讲述笔者在rk3568芯片上开发安全启动功能实践的流程。其中主要参考瑞芯微官方文档《Rockchip_Developer_Guide_Secure_Boot_for_UBoot_Next_Dev_CN.pdf》。文档中描述逻辑不是很清晰而且和当前瑞芯微的sdk中安全启动的流程匹配度不高。本文就不再对瑞芯微官方文档的内容…

[操作系统] 线程互斥

文章目录 背景概念线程互斥的引出互斥量锁的操作初始化 (Initialization)静态初始化动态初始化 加锁 (Locking)阻塞式加锁非阻塞式加锁 (尝试加锁/一般不考虑) 解锁 (Unlocking)销毁 (Destruction)设置属性 (Setting Attributes - 通过 pthread_mutex_init) 锁本身的保护互斥锁…

【神经网络与深度学习】两种加载 pickle 文件方式(joblib、pickle)的差异

引言 从深度学习应用到数据分析的多元化需求出发&#xff0c;Python 提供了丰富的工具和模块&#xff0c;其中 pickle 和 joblib 两种方式在加载数据文件方面表现尤为突出。不同场景对性能、兼容性以及后续处理的要求不尽相同&#xff0c;使得这两种方式各显优势。本文将通过深…

Electron 入门指南

Electron 入门指南 Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用的框架。通过 Electron&#xff0c;你可以利用 Web 技术开发出功能强大的桌面应用程序&#xff0c;并且能够运行在 Windows、Mac 和 Linux 系统上。 本文将带你从零开始构建一个简单的 Ele…

编程中如何与AI交互-结构化输入和理解确认机制

一 结构化输入是什么 &#x1f4cc; 结构化输入的定义&#xff1a; 结构化输入是指以清晰、分层、有逻辑的格式向 AI 输入信息&#xff0c;使其更容易解析内容、抓住重点&#xff0c;并准确回答问题。 &#x1f4e6; 举个例子&#xff08;编程场景&#xff09;&#xff1a; 非…

13:傅里叶变换

傅立叶变换(FT, Fourier Transform)的作用是将一个信号由时域变换到频域。其实就是把数据由横坐标时间、纵坐标采样值的波形图格式&#xff0c;转换为横坐标频率、纵坐标振幅(或相位)的频谱格式。换后可以很明显地看出一些原先不易察觉的特征。 有些信号在时域上是很难看出什么…

基于单片机的音频信号处理系统设计(一)

项目名称:基于单片机的音频信号处理系统设计学院名称:信息学院学生姓名:学号专业年级:指导教师:教师职称:教授企业导师:目 录 摘 要 Abstract 1 前言 1.1研究背景与意义 <

机器学习实操 第一部分 机器学习基础 第8章 降维技术

机器学习实操 第一部分 机器学习基础 第8章 降维技术 内容概要 第8章探讨了降维技术&#xff0c;这些技术在处理高维数据时至关重要。高维数据不仅会使训练过程变得极其缓慢&#xff0c;还会增加找到良好解决方案的难度&#xff0c;这就是所谓的维度灾难问题。幸运的是&#…

微信小程序 XSS 防护知识整理

场景1&#xff1a;用户输入表单&#xff08;如评论框&#xff09; 错误做法&#xff1a;直接渲染未过滤的用户输入 // WXML <view>{{ userInput }}</view>// JS&#xff08;用户输入了恶意内容&#xff09; Page({data: { userInput: <script>alert("…

MySQL 服务搭建

&#x1f4a2;欢迎来到张翊尘的开源技术站 &#x1f4a5;开源如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 在线安装Ubuntu/Debian更新系统包索引安装 MySQL …

【Java面试笔记:进阶】23.请介绍类加载过程,什么是双亲委派模型?

Java的类加载机制是JVM的核心组成部分,其过程分为三个阶段,并采用双亲委派模型来保证类加载的安全性和一致性。 1.类加载过程 1.加载阶段(Loading) 核心任务:查找并加载类的二进制字节流(如.class文件)。具体行为: 将字节码数据从不同数据源(如文件系统、网络等)读…

UN R79 关于车辆转向装置形式认证的统一规定(正文部分1)

UN R79法规是针对转向装置的型式认证法规&#xff0c;涉及A/B1/C类的横向控制辅助驾驶功能&#xff0c;对各功能的功能边界、性能要求、状态提示、故障警示以及型式认证要提交的信息做了规范&#xff0c;本文结合百度文心一言对法规进行翻译&#xff0c;并结合个人理解对部分内…