【动态规划篇】步步带你深入解答成功AC最优包含问题(通俗易懂版)

                       本篇小鸡汤:待到苦尽甘来时,我给你讲讲来时路。

 欢迎拜访羑悻的小杀马特.-CSDN博客

本篇主题:解答洛谷的最优包含问题

制作日期:2024.12.23

隶属专栏:C/C++题海汇总

 

目录

 本篇简介:

一·动态规划简述: 

1.1概念:

1.2基本原理:

 1.3使用步骤:

1.3.1定义状态:

1.3.2确定状态转移方程:

1.3.3确定初始状态:

1.3.4计算最终结果:

1.4应用场景: 

1.4.1资源分配问题:

​编辑​1.4.2最长公共子序列问题:

​编辑​

1.4.3字符串编辑距离问题:

二·题目叙述:

 ​编辑​

三·思路简述: 

四·解答代码:

五·动态规划算法基于本篇的总结:


 本篇简介:

通过对动态规划的理解,来利用状态转移方程,填充好dp二维数组,完成对本题:最优包含的解答,理解为什么这么列方程,以及其他的一些细节处理是怎么做到的。

一·动态规划简述: 

1.1概念:

动态规划(Dynamic Programming)是一种用于解决优化问题的算法策略。

1.2基本原理:

1.2.1分解问题: 1.2.2避免了重复计算:

 1.3使用步骤:

1.3.1定义状态:

1.3.2确定状态转移方程:

1.3.3确定初始状态:

1.3.4计算最终结果:

 

1.4应用场景: 

1.4.1资源分配问题:

​1.4.2最长公共子序列问题:

1.4.3字符串编辑距离问题:

也许说了这么大堆,大家还是不太了解,那么我们抛开这些概念,跟着博主的思路,去上手搞一下这道题,也许会慢慢理解自己对它的深奥之处了,这里我们就先记住就是假设前面我们已经知道答案了往后面的答案靠拢(当然也可以是知道后面的答案往前推,这里根据题目具体分析)

 

二·题目叙述:

 

测试用例:

输入:

ABCDEABCD
XAABZ

输出:

3

洛谷原题链接: [蓝桥杯 2019 国 B] 最优包含 - 洛谷

三·思路简述: 

 这道题目简单来说是什么?

就是给了我们两个串一个是主串为s;另一个是子串为t;让我们每次都可以对s操作(也就是把一个字符可以改掉,并且记录操作次数);最后使得它中存在有一个为t的子串(这里有点不同,它可以不相邻如s:abc ;t:ac 这样也可以的)。

那么此刻我们可能是没有思路,或者直接去说暴力去一个个遍历等,然而这里肯是不合理的;

​ 

看到数据后我们便停止了想法;博主是百般苦思,突然看到了:

​ 

凭之前做动态规划题的思路;一般只要出现最小最大等;肯定与它逃不了干系,然后就是它又是字符串,之前也做了很多关于字符串的动态规划;因此可以把这道题往这方面去想。

 这里由于是两个串,我们不妨设置二维dp;

dp数组含义:

dp[i][j]表示让s下标0-i对应的的子串中存在t的0-j这段串的最小操作次数

然后呢我们就是想方设法得出状态转移方程:

首先肯定大家对这一步很难想;但是这一步说白了它又是解答问题的关键;因此下面博主带大家思考如何写出:

首先我们假设已经到了i,j位置但是不一定s t两个子串同对应位置;然后我们根据这道题的题意可以得出应该是向前推,也就是后序的从前往后初始化dp数组。

下面请看图:

​   

通过上面的作图分析我们就得到了相关状态转移方程咯。

状态转移方程:

俗话说的好状态转移方程也算是动态规划问题的关键了。

初始化问题和填充二维dp数组: 

 我们要如何初始化dp数组呢?

首先我们要的是最小值,因此我们可以考虑先把它 初始化都为最大值:

这里博主使用的是memset这个库函数,因为它的对整形数组的值一个一个字节初始化的;因此我们使用的是:

 memset(dp, 0x3f, sizeof(dp));

这样每个整型就初始化成0x3f3f3f3f它不是整型最大值INT_MAX,那为什么不初始化后者呢?

①INT_MAX:

一般用于表示整数的上限,例如在一些需要检查整数是否溢出的情况,如计算两个整数相加时:

#include <iostream>
#include <climits>
int main() {int a = INT_MAX;int b = 1;if (a + b < 0) {std::cout << "Overflow occurred!" << std::endl;}return 0;
}

解释:上述代码检查 a + b 是否小于 0,因为如果 a 为 INT_MAX 且 b 为正数,它们相加会导致溢出,结果为负数,利用这个特性可以检测溢出。

②0x3f3f3f3f:

​ 1·在算法和动态规划中经常被用作一个较大的数,但又不是 INT_MAX 那么大。使用 0x3f3f3f3f 作为一个很大的数有一些优点。
 2·它是一个方便的数字,在使用 memset 函数初始化数组时,使用 memset(arr, 0x3f, sizeof(arr)) 可以将数组初始化为一个较大的值,而且两个 0x3f3f3f3f 相加不会溢出。
 

#include <iostream>
#include <cstring>
int main() {int arr[5];memset(arr, 0x3f, sizeof(arr));std::cout << arr[0] << " " << arr[1] << std::endl;int sum = 0x3f3f3f3f + 0x3f3f3f3f;std::cout << sum << std::endl;return 0;
}

解释:这段代码中,memset(arr, 0x3f, sizeof(arr)) 把 arr 数组中的元素初始化为 0x3f3f3f3f,0x3f3f3f3f + 0x3f3f3f3f 相加结果不会溢出,而如果使用 INT_MAX 相加会溢出。

 总结:
 INT_MAX 是 int 类型能表示的最大值,常用于表示整数范围的上限和溢出检查;
 0x3f3f3f3f 是一个很大的数,但比 INT_MAX 小,常用于算法中作为一个较大的初始值,尤其是在使用 memset 等函数初始化数组时,因为其具有方便计算和不易溢出的特点
下面就初始化完了吗,当然不是:

因为我们这样就会产生与定义不符;我们就看状态方程发现可以从1开始双层for循环遍历,当它下标是0难道一定符合题意吗?

 对于dp[0][j]:就是从s中的0个字符去找让它变成t中的前j个字符,然而明显是不可能的;故我们如果把它设置成很大的值这里把它想象成无穷大还是可以的。
但是对于dp[i][0]:这样还可以吗?肯定不行,因为这明显不用操作就好,因此还需要这种情况改成0。 

这样初始化就ok咯。

后面还有个优化处理:

我们为了让s[i],t[j]让它们下标正好对应的是第几个元素,有在前面加了个空字符(相当于虚拟节点):

 s = " " + s;//这里前面补上“ ”让后面访问s[i],t[j]直接就是它的第几个t = " " + t;

填充dp二维数组: 
此时就用我们的状态转移方程完成就好了。

下面我们就可以手搓出代码了吧;但是当博主根据测试范围给它卡空间开dp会发现有溢出风险:

这里由于我们会返回dp[n1][n2];最大不就才1000嘛;首先如果我们开1001理论可以的,但是就会 出现:

但尝试把它开大一个1002就可以了,可能有预留空间的意思把。

四·解答代码:

#include <bits/stdc++.h>
using namespace std;
//最值问题且为字符串,不妨动态规划:
//dp[i][j]表示让s下标0-i对应的的子串中存在t的0-j这段串的最小操作次数
int main() {string s, t;cin >> s >> t;s = " " + s;//这里前面补上“ ”让后面访问s[i],t[j]直接就是它的第几个t = " " + t;int n1 = s.size();int n2 = t.size();int dp[1002][1002];//多开一个,这里1001可能越界memset(dp, 0x3f, sizeof(dp));//初始化max因为要求min;//而且符合了题意比如dp[0][j]:这里表示从s的0-0;让它存在t的0-j;//这肯定是不存在的故可以想象成操作+oo才达到for (int i = 0; i <= n1; i++) dp[i][0] = 0;//符合一下定义//从s的0-i找t的0-0肯定是不用操作故为0for (int i = 1; i <= n1; i++) {for (int j = 1; j <= n2; j++)dp[i][j] = s[i] == t[j]? dp[i - 1][j - 1] : min(dp[i - 1][j - 1] + 1, dp[i - 1][j]);}cout << dp[n1][n2];return 0;
}

最终也是通过了:

 干货来袭:

五·动态规划算法基于本篇的总结:

 根据博主个人做了的动态规划题总结了几点,希望对大家学习这块有帮助:

1·联想到动态规划---->2·确定好状态转移方程(确定的时候根据题意判断是从前往后还是从后往前然后去找i-1或者i+1)---->3·初始化防越界(这里可以是一维dp或者二维dp,有可能原数组和dp数组下标不是一一对应关系,因此要处理好)----> 4·填充dp数组(根据状态转移方程,这里可能是从前往后遍历,也可以是从后往前遍历,根据题目具体分析)---->5·确定返回值---->6·再次检查dp数组是否还会存在越界---->7·可以选择做好滚动数组优化处理。

本篇的要点也就全部结束了,最后再次感谢大家的阅读,希望对大家学习动态规划以及基于这道题解答对大家有所帮助,感谢支持!!! 


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

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

相关文章

Intent--组件通信

组件通信1 获取子活动的返回值 创建Activity时实现自动注册&#xff01;【Activity必须要注册才能使用】 默认 LinearLayout 布局&#xff0c;注意 xml 中约束布局的使用&#xff1b; 若需要更改 线性布局 只需要将标签更改为 LinearLayout 即可&#xff0c;记得 设置线性布局…

table 表格转成 excell 导出

OK&#xff0c;功能非常简单&#xff0c;但是很实用啊&#xff01; 依赖安装 这里我们需要安装两个依赖&#xff1a; xlsx 和 file-saver&#xff0c;就可以帮助我们实现功能了&#xff01; npm i xlsx file-saver代码参考 导出方法 utils/index.js import * as XLSX from …

Vivado 编译(单核性能对比+高性能迷你主机+Ubuntu20.04/22.04安装与区别+20.04使用远程命令)

目录 1. 简介 2. 单核性能对比 2.1 PassMark 2.2 geekbench 2.3 CPU-7 2.4 选择 UM790 pro 3. Ubuntu 22.04 物理机 3.1 安装 Ubuntu 22.04 3.2 安装 Vitis 2022.1 3.3 缺点 4. Ubuntu 20.04 物理机 4.1 安装 Ubuntu 20.04 4.2 实用命令 4.2.1 SSH 保持活跃 4.2…

Java期末复习JDBC|网课笔记+校课总结

目录 1、概念 2、JDBC步骤 JDBC的基本步骤&#xff1a; 1、加载数据库驱动&#xff1a;通常使用Class类的forName()静态方法来加载驱动。 2、通过DriverManager获取数据库连接&#xff1a;需要传入3个参数&#xff1a;数据库URL、登陆数据库的用户名和密码。 3、通过Conn…

Require:离线部署 Sourcegraph

Sourcegraph 使读取、编写和修复代码变得容易——即使在庞大而复杂的代码库中。 代码搜索&#xff1a;搜索所有分支和所有代码主机的所有存储库。代码智能&#xff1a;导航代码、查找引用、查看代码所有者、跟踪历史记录等。修复和重构&#xff1a;一次对许多存储库进行大规模更…

element ui--下拉根据拼音首字母过滤

很多场景下我们的下拉不仅仅要根据选项中的字过滤&#xff0c;还要根据拼音首字母过滤&#xff0c;现在我们来实现下。 要获取汉字拼音&#xff0c;可以用pinyin-pro库来实现 1.导入拼音库 npm install pinyin-pro 下面的代码可以获取companyName的拼音&#xff0c;返回的是…

Vue3 中使用axios

1.安装axios、js-cookie、pinia axios命令行&#xff1a; npm install axios js-cookie命令行&#xff1a; npm install js-cookie store命令行&#xff1a; npm install pinia 2.配置文件 (1)缓存文件配置 src/plugins/auth.js const sessionCache {set (key, valu…

从AI换脸到篡改图像,合合信息如何提升视觉内容安全?

本文目录 引言一、AI“真假之战”下的发展现状与考验挑战1.1 视觉内容安全现状与技术分类1.2视觉内容安全企业1.3视觉内容安全领域挑战 二、开山之石&#xff1a;引领视觉内容安全的创新之路2.1合合内容安全系统2.2发起编制相关技术规范2.3参与篡改检测挑战赛 三、视觉内容安全…

解决Ubuntu下无法装载 Windows D盘的问题

电脑安装了 Windows 和 Ubuntu 24.04 后&#xff0c;在Ubuntu系统上装载 D盘&#xff0c;发现无法装载错误如下&#xff1a; Error mounting /dev/nvme0n1p4 at /media/jackeysong/Data: wrong fs type, bad option, bad superblock on /dev/nvme0n1p4, missing codepage or h…

STM32-笔记10-手写延时函数(SysTick)

1、什么是SysTick Systick&#xff0c;即滴答定时器&#xff0c;是内核中的一个特殊定时器&#xff0c;用于提供系统级的定时服务。该定时器是一个24位的倒计数定时器‌。它从设定的初值&#xff08;即重载值&#xff09;开始计数&#xff0c;每经过一个系统时钟周期&#xff0…

“AI+Security”系列第4期(一)之“洞” 见未来:AI 驱动的漏洞挖掘新范式

在数字化浪潮下&#xff0c;安全漏洞问题日益严峻&#xff0c;成为各行业发展的重大挑战。近日&#xff0c;“AISecurity” 系列第 4 期线下活动于北京成功举办&#xff0c;聚焦 “洞” 见未来&#xff1a;AI 驱动的漏洞挖掘新范式&#xff0c;汇聚了安全领域的众多专家。 本次…

攻防世界 PHP2

开启场景 访问 /index.php&#xff0c;页面无变化 访问 /index.phps index.php 和 index.phps 文件之间的主要区别在于它们的文件扩展名。 index.php&#xff1a;这是一个标准的 PHP 文件&#xff0c;通常用于编写 PHP 代码。当用户访问 index.php 文件时&#xff0c;Web 服务器…

AI应用-本地模型实现AI生成PPT(简易版)

文章目录 前言技术栈效果展示 一、实现思路二、实现步骤1.本地安装marp-cli2.后端实现3.前端实现 三、代码地址及说明 前言 在许多项目中&#xff0c;生成 PPT 是常见的需求&#xff0c;尤其在教育和报告展示中。传统的生成 PPT 的方法需要手动创建&#xff0c;而使用生成模型…

项目2路由交换

背景 某学校为满足日常教学生活需求&#xff0c;推动数字校园的建设&#xff0c;学校有办公楼和学生宿舍楼和服务器集群三块区域&#xff0c;请合理规划IP地址和VLAN&#xff0c;实现企业内部能够互联互通现要求外网能通过公网地址访问服务器集群&#xff0c;学生和老师能正常…

快速掌握Haproxy原理架构

文章目录 一、原理架构二、无负载均衡三、四层负载均衡的工作流程四、七层负载均衡工作流程五、基础属性mode 属性retries 属性maxconn 属性clitimeout 属性servtimeout 属性states uri 属性 一、原理架构 四层tcp代理&#xff1a;Haproxy仅在客户端和服务器之间双向转发流量&…

02、并发编程的三大特性

并发编程有三大特性分别是&#xff0c;原子性&#xff0c;可见性&#xff0c;有序性。会产生这些特性的根本原因是现在的服务器都是多CPU多核心数的&#xff0c;每个CPU都有自己单独的一套缓存和pc系统&#xff0c;而且程序在运行时按照JMM的规范&#xff0c;它们是需要先把数据…

【项目构建】Gradle入门

本文适用&#xff1a; 不知道什么是项目构建&#xff0c;可以了解下Ant&#xff0c;Maven&#xff0c;Gradle的区别。知道什么是项目构建&#xff0c;了解Ant&#xff0c;Maven&#xff0c;可以看到Gradle是怎么做的。知道什么是项目构建&#xff0c;了解Ant&#xff0c;Maven&…

java栈--数据结构

前言 java实现数据结构栈&#xff1a;用顺序表存储的栈和数组存储的栈。 本文源代码网址&#xff1a;https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack https://gitee.com/zfranklin/java/tree/master/dataStructure/src/com/njupt/stack 栈…

2.5.2 文件结构、目录及存取

文章目录 文件结构文件目录存取 文件结构 文件结构是文件的组织形式。从用户角度观察到的结构是逻辑结构&#xff0c;从机器实现存储的角度观察&#xff0c;看到的是物理结构。 逻辑结构 有结构的记录式文件&#xff1a;文件中记录的长度都相同&#xff0c;称为定长记录。文件…

关于科研中使用linux服务器的集锦

文章目录 常用的linux命令下载COCO2017数据集 常用的linux命令 一个文件移动到另一个目录下的命令是&#xff1a;mv -v ./old_name ./new_name 如果目标文件夹中已经有同名文件或文件夹&#xff0c;mv 会覆盖它们&#xff08;除非使用了 -i 选项来提示确认&#xff09;。 使用…