[算法学习记录] 动态规划基础、01背包、完全背包、多重背包

news/2025/3/25 21:20:14/文章来源:https://www.cnblogs.com/Pingjiadoge/p/18790138

何为动态规划

动态规划的核心思想是利用已知信息逐步推导未知信息,像斐波那契数列就是典型的根据已知推未知的问题。在动态规划的过程中,我们围绕着一个数组或表格进行操作,需要明确我们要维护的状态,状态的初始化,以及状态的转移,像斐波那契数列的状态就是数字,初始化就是第一、二位都为1,而状态的转移就是从第三位开始,每一位都等于前两位之和。

状态的定义

状态需要满足无后效性,即状态一旦确定,之后的操作都不会改变已有的状态,且之后的状态只能有先前的状态转移过来。

状态转移方程

状态转移方程就是状态转移的方式,像斐波那契数列,状态转移方程就是f[i] = f[i-1] + f[i-2].

解题的基本步骤

对于DP问题,我们一般按照确定状态定义确定状态转移方程确定初始状态确定答案状态这个步骤进行。

简单的DP问题——背包DP

背包问题是最简单的一类动态规划问题,根据每种物品的数量可以分为01背包(每种物品只有一个,每个物品只有选与不选两种状态)完全背包(每种物品的数量有无限个)多重背包(每种物品有有限个)

01背包

如何在有限的背包容量下选择有着一定体积的物体并求得最大总价值,这是01背包问题的一般形式,之所以叫它01背包,是因为每个物品只有选择与不选择两种状态,分别对应二进制的0和1。我们用一个例题来详细讲解:
例题 星码 采药
本题是一个典型的01背包问题,根据做题步骤,很容易就能发现状态就是一件物品的选择与否,状态转移方程就是当前总价值与选择后的总价值之间的最大值,而状态的初始化就是,背包总价值为0,总重量也为0,而答案所要的状态是在有限的背包容量下使背包总价值最大,参考代码如下:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e3+5;
int w[N],v[N],dp[N],t,m;
//w代表体积,v代表价值,dp为状态
void solve()
{for(int i = 1;i<=t;i++) dp[i] = 0;//状态的初始化,初始状态背包为空for(int i = 1;i<=m;i++)	cin >> w[i] >> v[i];for(int i = 1;i<=m;i++)for(int j = t;j>=w[i];j--)dp[j] = max(dp[j],dp[j-w[i]] + v[i]);//j代表当前背包的容量//状态的转移,我们这里采用了滚动数组(新状态会覆盖旧状态)进行优化,为了确保dp[j-w[i]]是上一个状态我们需要倒序操作,//如果正序操作,在计算dp[j]时dp[j-w[i]]就已经被新状态覆盖了假设j = 7,w[i] = 3,很容易就能发现,当j = 8时,它的上一个状态dp[4]已经被修改过//j>=w[i]是为了防止数组越界cout << dp[t] <<"\n";//最终状态即为背包容量为t时价值的最大值
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);while (cin >> t >> m){if(t==0 && m==0)break;solve();}//本题有多个样例,且在t,m均为0时终止运行return 0;
}

完全背包

与01背包不同,完全背包的每种物品都各有无限个,体现在题目中,我们在使用滚动数组解题时,将倒序操作改为正序操作,在01背包问题中,这样可能会导致重复计算,但在完全背包问题中,我们要的就是重复计算,所以只需要对01背包问题的代码稍加修改即可解决完全背包问题。
例题 星码 无穷背包

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5+5;
int m, n,w[505],v[505],dp[N];
//w是物品的体积,v是价值,dp是状态数组
void solve()
{cin >> m >> n;for(int i = 1;i<=n;i++)cin >> w[i] >> v[i];for(int i = 1;i<=n;i++)for(int j = v[i];j<=m;j++) dp[j] = max(dp[j],dp[j-v[i]]+w[i]);//只有j(当前背包容量)大于v[i]时才能考虑装载新物品,所以j直接从v[i]开始//由于每种物品都有无数个,所一01背包问题中正序操作的重复问题就成了我们解题的捷径,为了打倒最终状态,我们可以一直向背包中装入某种物品cout << dp[m] <<"\n";//最终状态,当背包容量为m时的最大价值
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _ = 1;while(_--)solve();return 0;
}

多重背包

多重背包的每种物品有有限个,但我们可以把每个物品都归为一“类”使多重背包问题转化为01背包问题。转化的方式有很多种,如果数据量较小,可以直接重复添加一类物品多次;如果数据量较大,则可考虑利用二进制的性质(每个十进制数都能由二进制表示)对数据进行压缩,以优化时间复杂度。
例题 星码 多重背包
本题的数据量较小,最多有1e4“类”物品,所以我们可以直接暴力存储这些“类”,在完成数据存储后,按照01背包的方法即可解答。


#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e4+10;
int m,n,x,y,z,w[N],v[N],t = 0;
ll dp[N];void solve()
{for(int i = 0;i<=m;i++)dp[i] = 0;//初始化状态,什么都不选时价值为0cin >> m >> n;while(n--){cin >> x >> y >> z;//x,y,z分别是数量、价值、体积while(x--){w[++t] = y;v[t] = z;}//把每件物品都看做一“类”}for(int i = 1;i<=t;i++)for(int j = m;j>=v[i];j--)dp[j] = max(dp[j],dp[j-v[i]]+w[i]);//01背包的标准做法,不过要注意,此时物品的种类数从n(此时n为0)变成了t		cout << dp[m] <<"\n";//输出背包容量为m时,背包所能容纳的最大价值
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _ = 1;while(_--)solve();return 0;
}

例题 星码 多重背包二周目

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e6+9;
int n,m,s,w,v,a[N],b[N],t = 0;
ll dp[N];
//数据量较大,给状态开long long防止溢出
void solve()
{cin >> m >> n;//m,n分别是背包容量,物品种类while(n--){cin >> s >> w >> v;//s,w,v分别是数量、价值、体积int k = 1;while(k<=s){b[++t] = w*k;a[t] = v*k;s-=k;k*=2;}//任意十进制数都能由二进制数表示if(s>0){b[++t] = w*s;a[t] = v*s;}//若干次分割后,可能会有余量,通常较小,可以直接添加到数组中}for(int i = 1;i<=t;i++)for(int j = m;j>=a[i];j--)dp[j] = max(dp[j],dp[j-a[i]]+b[i]);//01背包的标准做法cout << dp[m] <<"\n"; 
}int main()
{ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int _ = 1;while(_--)solve();return 0;
}

本人初学算法,能力有限,如有纰漏,敬请指正。

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

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

相关文章

在HTML页面通过JavaScript访问Ollama本地部署的DeepSeek

在HTML页面通过JavaScript访问Ollama本地部署的DeepSeek,顺便解决了 HTML 页面调用 Ollama 服务的跨域问题前排提醒: 1. 操作系统为Windows11 2. 如果你还没有使用Ollama本地部署DeepSeek,可以参考Windows系统上使用Ollama本地部署DeepSeek 3. 顺便解决了 HTML 页面调用 Oll…

【3】进制转换学习总结(c++)

1.进制的基础知识 一:进制是进位计数制,是人为定义的带进位的计数方法。对于任何一种进制,例如:X进制,就表示每一位置上的数运算时都是逢X进一位。比如十进制就是逢十进一,二进制就是逢二进一。 二:生活中常见的进制有:十进制,十二进制,二十四进制,六十进制等。 2.十…

vue+leaflet示例:地图截图批量导出(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

智能Agent如何改造传统工作流:从搜索到全能助手

智能Agent如何改造传统工作流:从搜索到全能助手 引言:当AI遇上工作流 还记得我们以前搜索信息的方式吗?输入关键词,浏览大量结果,筛选有用内容,再整合成我们需要的答案。这个过程不仅耗时,还常常让人感到疲惫。 如今,智能Agent的出现正在彻底改变这一切。想象一下,你只…

vue+leaflet示例:拓展wms以及wmts地图范围裁剪(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:快速渲染聚合矢量瓦片(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:热力图(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:地图全图以及框选截图导出功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:聚合图功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:结合geoserver利用WFS服务实现图层新增功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:结合geoserver利用WFS服务实现图层编辑功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

IDEA使用Docker插件打包+推送+部署

前提条件:在服务器或者虚拟机中已经安装好了Docker1、确认是否安装插件2、配置SSH链接信息3、构建一个简单的SpringBootDemo工程4、编写一点测试代码 @RestController public class HelloController {@GetMapping("/hello")public String hello(){return "<…