和AI聊天:动态规划

动态规划

动态规划(Dynamic Programming,简称 DP)是一种常用于优化问题的算法。它解决的问题通常具有重叠子问题和最优子结构性质,可以通过将问题分解成相互依赖的子问题来求解整个问题的最优解。
动态规划算法主要分为以下几个步骤:

  1. 定义状态:将问题描述成一个状态模型,包括状态变量和状态转移方程。
  2. 初始化:将状态模型中的变量初始化为特定的值。
  3. 状态转移:根据状态转移方程,通过之前的状态计算当前状态的值。
  4. 计算最优解:通过计算得到最终的最优解。

动态规划算法的优点在于它可以避免重复计算,因此在处理复杂的问题时特别有用。然而,它的缺点在于,由于需要存储中间结果,它可能需要更多的空间来存储数据。

动态规划经典问题

以下是一些经典的动态规划问题:

  1. 最长公共子序列(LCS):给定两个字符串,求它们的最长公共子序列。
  2. 最长递增子序列(LIS):给定一个序列,求它的最长递增子序列。
  3. 背包问题:给定一个背包和一组物品,每个物品有重量和价值,求在不超过背包容量的情况下,能够获得的最大价值。

最长公共子序列(LCS)

最长公共子序列(LCS)问题是求解两个序列的最长公共子序列,即两个序列中都出现的最长的子序列。下面介绍一种常见的基于动态规划算法的求解方法:

令 m 和 n 分别为两个序列的长度,令 c[i][j] 表示第一个序列前 i 个元素和第二个序列前 j 个元素的 LCS 的长度,则有以下状态转移方程:

c[i][j] = c[i-1][j-1] + 1 (当第一个序列的第 i 个元素等于第二个序列的第 j 个元素时)
c[i][j] = max(c[i-1][j], c[i][j-1]) (当第一个序列的第 i 个元素不等于第二个序列的第 j 个元素时)

可以看出,当两个序列的当前元素相同时,LCS 长度加 1,否则 LCS 长度不变。因此,可以根据这个状态转移方程填充整个 c 数组。

最终,LCS 的长度即为 c[m][n],而具体的 LCS 可以通过反向追溯 c 数组得到。具体地,从 c[m][n] 开始,如果 c[i][j] 等于 c[i-1][j-1] + 1,则说明第一个序列中第 i 个元素和第二个序列中第 j 个元素都是 LCS 的元素之一,将它们加入 LCS 中;否则,根据 c[i][j] 是否等于 c[i-1][j] 或 c[i][j-1] 确定向左或向上移动。

这个算法的时间和空间复杂度均为 O(mn)。

以下是基于动态规划算法的最长公共子序列(LCS)问题的 C++ 代码实现:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;int lcs(string s1, string s2) {int m = s1.length(), n = s2.length();int c[m+1][n+1];for (int i = 0; i <= m; i++)c[i][0] = 0;for (int i = 0; i <= n; i++)c[0][i] = 0;for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (s1[i-1] == s2[j-1])c[i][j] = c[i-1][j-1] + 1;elsec[i][j] = max(c[i-1][j], c[i][j-1]);}}return c[m][n];
}int main() {string s1 = "AGGTAB";string s2 = "GXTXAYB";cout << "LCS length: " << lcs(s1, s2) << endl;return 0;
}

运行结果为:

LCS length: 4

说明 “GTAB” 是两个序列的最长公共子序列。

最长递增子序列(LIS)

最长递增子序列(Longest Increasing Subsequence,LIS)问题是一个经典的动态规划问题。下面是具体的解法及C++代码实现。

一、解法

设dp[i]为以第i个元素为结尾的最长递增子序列的长度。dp[i]的值为前i-1个数中,所有比第i个数小的数的dp值加1的最大值。

以一个序列 { 5,3,4,8,6,7 }为例:

  • dp[1] = 1;(序列:5)
  • dp[2] = 1;(序列:3)
  • dp[3] = 2;(序列:3,4)
  • dp[4] = 3;(序列:3,4,8)
  • dp[5] = 3;(序列:3,4,6)
  • dp[6] = 4;(序列:3,4,6,7)

二、C++代码

#include <iostream>
#include <vector>
using namespace std;int lengthOfLIS(vector<int>& nums) {if (nums.empty()) return 0;int n = nums.size();vector<int> dp(n, 1); // 其中dp[i]表示以i结尾的最长递增子序列的长度,初始值都为1int res = 1;for (int i = 1; i < n; i++) { // 遍历到ifor (int j = 0; j < i; j++) { // 遍历到i之前的每个数if (nums[j] < nums[i]) {dp[i] = max(dp[i], dp[j]+1); // 更新最长递增子序列的长度}}res = max(res, dp[i]); // 更新最长递增子序列的长度的最大值}return res;
}int main() {vector<int> nums = {5, 3, 4, 8, 6, 7};cout << lengthOfLIS(nums) << endl; // 输出4return 0;
}

上述代码中使用了vector容器,可以方便的实现动态数组。

背包问题

一、01背包问题

给定n个物品和一个容量为W的背包,物品i的重量为wt[i],价值为val[i]。现在要求选若干件物品放入背包,使得放入的物品总重量不超过W,且价值最大。

01背包问题需要使用动态规划求解。设dp[i][j]表示前i个物品中,在总重量不超过j的情况下的最大价值。则有以下状态转移方程:

  • 如果当前选的物品重量大于当前背包总重量,则不能选这个物品:dp[i][j] = dp[i-1][j]

  • 否则,可以选或不选这个物品,取决于是否可以使总价值更大:

    a. 选这个物品,总重量为j,则总价值为dp[i-1][j-wt[i]]+val[i]

    b. 不选这个物品,则总价值为dp[i-1][j]

    最终取dp[n][W]即为所求答案。

二、完全背包问题

完全背包问题和01背包问题的区别在于,每个物品可以选择无限次。设dp[i][j]表示前i个物品中,在总重量不超过j的情况下的最大价值。则有以下状态转移方程:

  • 如果当前选的物品重量大于当前背包总重量,则不能选这个物品:dp[i][j] = dp[i-1][j]

  • 否则,可以选或不选这个物品,取决于是否可以使总价值更大:

    a. 选这个物品,总重量为j,则总价值为dp[i][j-wt[i]]+val[i]

    b. 不选这个物品,则总价值为dp[i-1][j]

    最终取dp[n][W]即为所求答案。

三、多重背包问题

多重背包问题和01背包问题的区别在于,每个物品的数量有限制。设dp[i][j]表示前i个物品中,在总重量不超过j的情况下的最大价值。则有以下状态转移方程:

  • 如果当前选的物品重量大于当前背包总重量,则不能选这个物品:dp[i][j] = dp[i-1][j]

  • 否则,可以选或不选这个物品,取决于是否可以使总价值更大:

    a. 选这个物品,总重量为j,则总价值为dp[i][j-wt[i]]+val[i]

    b. 不选这个物品,则总价值为dp[i-1][j]

    需要注意的是,在更新dp[i][j]的时候,需要使用max函数比较选或不选这个物品的价值。同时,如果每个物品的数量有限制,还需要对物品数量进行处理。最终取dp[n][W]即为所求答案。

四、C++代码

01背包问题:

#include <iostream>
#include <vector>
using namespace std;int knapsack01(int W, vector<int>& wt, vector<int>& val) {int n = wt.size();vector<vector<int>> dp(n+1, vector<int>(W+1, 0)); // 初始化为0for (int i = 1; i <= n; i++) {for (int j = 1; j <= W; j++) {if (wt[i-1] > j) { // 当前选的物品重量大于当前背包总重量,不能选这个物品dp[i][j] = dp[i-1][j];} else {dp[i][j] = max(dp[i-1][j], dp[i-1][j-wt[i-1]]+val[i-1]); // 取选或不选这个物品的最大价值}}}return dp[n][W];
}int main() {int W = 10;vector<int> wt = {2, 2, 6, 5, 4};vector<int> val = {6, 3, 5, 4, 6};cout << knapsack01(W, wt, val) << endl; // 输出15return 0;
}

完全背包问题:

#include <iostream>
#include <vector>
using namespace std;int knapsackCom(int W, vector<int>& wt, vector<int>& val) {int n = wt.size();vector<vector<int>> dp(n+1, vector<int>(W+1, 0)); // 初始化为0for (int i = 1; i <= n; i++) {for (int j = 1; j <= W; j++) {if (wt[i-1] > j) { // 当前选的物品重量大于当前背包总重量,不能选这个物品dp[i][j] = dp[i-1][j];} else {dp[i][j] = max(dp[i-1][j], dp[i][j-wt[i-1]]+val[i-1]); // 取选或不选这个物品的最大价值}}}return dp[n][W];
}int main() {int W = 10;vector<int> wt = {2, 2, 6, 5, 4};vector<int> val = {6, 3, 5, 4, 6};cout << knapsackCom(W, wt, val) << endl; // 输出24return 0;
}

多重背包问题:

#include <iostream>
#include <vector>
using namespace std;int knapsackMul(int W, vector<int>& wt, vector<int>& val, vector<int>& cnt) {int n = wt.size();vector<vector<int>> dp(n+1, vector<int>(W+1, 0)); // 初始化为0for (int i = 1; i <= n; i++) {for (int j = 1; j <= W; j++) {if (wt[i-1] > j) { // 当前选的物品重量大于当前背包总重量,不能选这个物品dp[i][j] = dp[i-1][j];} else {for (int k = 0; k <= cnt[i-1]; k++) { // 对物品数量进行处理if (k*wt[i-1] > j) break; // 超过容量,退出循环dp[i][j] = max(dp[i-1][j], dp[i-1][j-k*wt[i-1]]+k*val[i-1]); // 取选或不选这个物品的最大价值}}}}return dp[n][W];
}int main() {int W = 10;vector<int> wt = {2, 2, 6, 5, 4};vector<int> val = {6, 3, 5, 4, 6};vector<int> cnt = {2, 3, 1, 4, 3};cout << knapsackMul(W, wt, val, cnt) << endl; // 输出54return 0;
}

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

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

相关文章

Java数组(未完待续)

诸神缄默不语-个人CSDN博文目录 我写Java的一天&#xff0c;是复健的一天。 很难想象我本科考96分的一门课&#xff0c;在区区5年之后&#xff0c;我就忘得这么彻彻底底。 数组Array&#xff1a;用来存储固定大小的同类型元素 文章目录 1. 创建数组2. 数组转字符串其他本文撰…

layui 新增tab标签页

// $("#fjyj").click(function () {// //window.location.href "/sysconfig/SuperVisorEdit";// navigateToTeamPersonModule(/CollectData/GradeWarning/EduIndex, 分级预警);// });function navigateToTeamPersonModule(url, name) {var ids n…

如何截取视频中的一段视频?分享几种视频分割方法

当处理长视频时&#xff0c;视频分割可以使您更加高效。如果您只需要处理其中的一部分&#xff0c;而不是整个视频&#xff0c;那么分割视频可以使您更容易找到需要处理的部分。而且&#xff0c;分割视频还可以使您更容易在不同的项目之间重复使用视频片段。教大家几种简单的视…

基于blockqueue的生产和消费模型

线程篇下讲的是基于阻塞队列的生产者消费者模型。在学习这个之前我们先了解一些其他概念&#xff1a; 同步&#xff1a;在保证数据安全的条件下&#xff0c;让线程按某种特定的顺序依次访问临界资源。 通过上一节的代码我们实现了一个多线程抢票的程序&#xff0c;但结果显示…

分布式锁之redis实现

docker安装redis 拉取镜像 docker pull redis:6.2.6 查看镜像 启动容器并挂载目录 需要挂在的data和redis.conf自行创建即可 docker run --restart always -d -v /usr/local/docker/redis/redis.conf:/usr/local/etc/redis/redis.conf -v /usr/local/docker/redis/data:/dat…

运算符与逻辑分支

2.运算符与逻辑分支 持续更新中… 运算符 1.进制转换 .toString() 10进制转换为其他进制 parseInt() 其他进制转换为10进制 进制: 二进制: 0, 1 (0~1) 八进制: 0, 1, 2, 3, 4, 5, 6, 7 (0~7) 十进制: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 (0~9) 十六进制: 0, 1, 2, 3, 4, 5, 6,…

使用 【jacoco】对基于 SpringBoot 和 Dubbo RPC 的项目生成测试覆盖率报告:实践+原理

基于 Dubbo RPC 的项目中有一个提供者项目backend、一个消费者项目gateway、以及注册中心nacos。本篇文章记录在windows本地对该框架的测试过程&#xff0c;以及介绍jacoco的基本原理 测试过程 官网下载安装包解压到本地&#xff0c;https://www.jacoco.org/jacoco/ 只需要用…

Android键盘监听

拦截键盘可在Activity中重写onKeyDown方法 常用的KeyCode有 KEYCODE_ALL_APPS 多任务管理键 KEYCODE_HOME Home键 KEYCODE_BACK 返回键 KEYCODE_POWER 电源键 KEYCODE_VOLUME_UP 加音量键 KEYCODE_VOLUME_DOWN 减音量键还有相机键、菜单键、查找键、&#xff08;上&…

11. Junit

我们主要学习的是 Junit5. 1. selenium 和 Junit 之间的关系 selenium 和 Junit 之间的关系 就像 Java 和 JavaScript 之间的关系&#xff0c;也就是没有关系。 为什么学习了 selenium 还要学习 Junit 呢&#xff1f; 举个例子&#xff0c;如果 Selenium 编写的自动化测试用…

论坛系统公共组件部分

1.在Java⽬录下创建包&#xff0c;在Resources⽬录下创建⽂件夹&#xff0c;结构如下 ├─java # java⽂件区 │ └─com │ └─example │ └─demo │ ├─common # 公共类 │ ├─config # 配置…

MySQL表操作

目录 一、创建mysql表的结构 1.在mydb数据库下创建一个表格名字为stu_info&#xff0c;里面结构包含了学号和姓名的名称&#xff0c;字符型以及他的引擎为innodb 字符集为gbk 校队规则为gbk_chinese_ci 二、数据库表查看的基本用法语句 1.查看数据库表明 2.查看数据库表的结…

数字图像处理:亮度对比度-几何变换-噪声处理

文章目录 数字图像增强亮度与对比度转换几何变换图像裁剪尺寸变换图像旋转 噪声处理添加噪声处理噪声 数字图像增强 亮度与对比度转换 图像变换可分为以下两种&#xff1a; 点算子&#xff1a;基于像素变换&#xff0c;在这一类图像变换中&#xff0c;仅仅根据输入像素值计算…

c++中的常用知识点总结

命名空间 使用命名空间之后&#xff0c;调用代码时可以省去也可以不省去相关的前缀。 #include <iostream>using namespace std;//使用c自己的命名空间 int main() {int num1 10;std::cout << "Hello, World!" << std::endl;cout<<num1&l…

【计算机网络】 ARP协议和DNS协议

文章目录 数据包在传输过程中的变化过程单播组播和广播ARP协议ARP代理免费ARP路由数据转发过程DNS协议 数据包在传输过程中的变化过程 在说ARP和DNS之前&#xff0c;我们需要知道数据包在传输过程的变化过程 从图片中可以看到&#xff0c;发送方的原数据最开始是在应用层&…

【元宇宙】区块链,元宇宙最大化的驱动力

如今&#xff0c;一些观察者认为区块链是在结构上实现元宇宙的必要条件&#xff0c;而其他人则认为这种说法是荒谬的。人们对于区块链技术本身仍然有很多困惑&#xff0c;所以根本谈不上清楚地了解込块链技术与元宇宙的关系。所以&#xff0c;我们可以从区块链的定义开始介绍。…

vscode使用delve调试golang程序

环境配置 delve仓库&#xff0c;含有教程&#xff1a;https://github.com/go-delve/delve golang的debugging教程&#xff1a;https://github.com/golang/vscode-go/wiki/debugging > go version go version go1.20 windows/amd64> go install github.com/go-delve/de…

华为云Stack的学习(五)

六、华为云stack服务简介 1.云服务在华为云Stack中的位置 云服务对接多个数据中心资源池层提供的资源&#xff0c;并向各种行业应用提供载体。 2.华为云Stack通用服务 2.1 云计算的服务模式 2.2 计算相关的云服务 2.3 存储相关的云服务 2.4 网络相关的云服务 3.云化案例 **…

如何取消KEIL-MDK工程中出现的CMSIS绿色图标

如何取消KEIL-MDK工程中出现的CMSIS绿色图标&#xff1f;我以前经常遇到&#xff0c;不知道怎么搞&#xff0c;好像也不影响编译结果。以前问过其他人&#xff0c;但是不知道怎么搞&#xff0c;相信很多人也遇到过。水平有限&#xff0c;表达不清楚&#xff0c;见下图&#xff…

Bootstrap的标题类(标题样式h1~h6)

Bootstrap 的标题字体大小通常遵循以下样式规则&#xff1a; h1 标题的字体大小为 2.5rem&#xff08;40像素&#xff09;。h2 标题的字体大小为 2rem&#xff08;32像素&#xff09;。h3 标题的字体大小为 1.75rem&#xff08;28像素&#xff09;。h4 标题的字体大小为 1.5re…

SOME/IP 支持两种序列化方式:TLV 和 TV

SOME/IP 是一种基于 IP 的可扩展面向服务的中间件协议,它可以在车载以太网中实现 ECU 之间的高效通信和互操作性。 SOME/IP 的序列化方式是指将数据结构或对象按照一定的规则转换成字节序列的过程,以便在网络中传输和解析。 SOME/IP 支持两种序列化方式:TLV 和 TV。 TLV是…