【动态规划篇】步步带你深入解答成功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肯定是不用操作故为0
    for (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·可以选择做好滚动数组优化处理。

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


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大语言模型】ACL2024论文-29 答案即所需:通过回答问题实现指令跟随的文本嵌入

【大语言模型】ACL2024论文-29 答案即所需&#xff1a;通过回答问题实现指令跟随的文本嵌入 目录 文章目录 目录文章信息摘要研究背景问题与挑战如何解决创新点算法模型实验效果推荐阅读指数&#xff1a;★★★★☆ 后记 文章信息 答案即所需&#xff1a;通过回答问题实现指令…

模型的量化(Quantization)

文章目录 一、浮点数格式&#xff1a;FP64, FP32, FP16, BFLOAT16, TF32之间的相互区别1、关于浮点数2、常见的浮点数格式 二、量化&#xff08;Quantization&#xff09;1、基本概念2、量化的实现8bit量化4bit量化 三、QLora四、大语言模型量化方法对比&#xff1a;GPTQ、GGUF…

10. zynq应用开发--camke编译

使用SDK工具 如果只做 Linux 应用开发&#xff0c;只需要一个 sdk.sh 文件即可&#xff0c;可以脱离 Petalinux 和 Vitis&#xff0c;也可以编译其三方的应用&#xff0c;可以说一劳永逸。 配置根文件系统 petalinux-config -c rootfs 编译SDK petalinux-build --sdk Linux主…

CSS学习记录20

CSS 3D 转换 通过CSS transform 属性&#xff0c;您可以使用以下3D转换方法&#xff1a; rotateX()rotateY()rotateZ() rotateX() 方法 rotateX() 方法使元素绕其X轴旋转给定角度&#xff1a; #myDiv {transform: rotateX(150deg); } rotateY() 方法 rotateY() 方法使元…

开发微信小程序的过程与心得

起因 作为家长&#xff0c;我近期参与了学校的护学岗工作。在这个过程中&#xff0c;我发现需要使用水印相机来记录护学活动&#xff0c;但市面上大多数水印相机应用都要求开通会员才能使用完整功能。作为一名程序员&#xff0c;我决定利用自己的技术背景&#xff0c;开发一个…

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…

数据可视化echarts学习笔记

目录&#xff0c;介绍 知识储备 一端操作&#xff0c;多端联动的效果&#xff08;开启了多个网页&#xff0c;操作一端&#xff0c;多个网页的效果会跟着改变&#xff09; cmd命令控制面板返回上一级或上上级 在当前目录打开文件&#xff1a; cd 文件名 在Windows命令提示符&am…

踏踏实实练SQLday1-1连续登录

踏踏实实练SQLday1 1连续登录1.1查询连续登录3天以上的用户第一步去重第二步-开窗rownumber&#xff0c;用date减一下&#xff0c;对结果进行分组 -- over()开窗函数知识图谱第三步 1.2查询连续登录最大天数用户1.3某个用户连续登录天数注意先where一下这个用户的数据过滤出来.…

Vue开发环境搭建上篇:安装NVM和NPM(cpnm、pnpm)

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II NPM永久使用淘宝源安装 cnpm安装pnpm【推荐】see also: vscode常用插件引言 淘宝镜像:http://npm.taobao.org 和 http://registry.npm.taobao.org 已在 2022.06.3…

数据仓库工具箱—读书笔记02(Kimball维度建模技术概述03、维度表技术基础)

Kimball维度建模技术概述 记录一下读《数据仓库工具箱》时的思考&#xff0c;摘录一些书中关于维度建模比较重要的思想与大家分享&#x1f923;&#x1f923;&#x1f923; 第二章前言部分作者提到&#xff1a;技术的介绍应该通过涵盖各种行业的熟悉的用例展开&#xff08;赞同…

Postman接口测试02|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 五、Postman 1、安装 2、postman的界面介绍 六、Postman执行接口测试 1、请求页签 3、响应页签 七、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作 八、接口关联 1、第一种方式&#xff1a;Json提取器 2、第二种方…

Oracle 日常巡检

1. 检查服务器状态 1.1. CPU使用情况 1.1.1. top top 命令是 Linux 和 Unix 系统中用于显示实时系统状态的工具&#xff0c;特别是对于监控 CPU 和内存的使用非常有用。 在命令行中输入 top&#xff0c;top 会显示一个实时更新的界面&#xff0c;其中包含系统的关键指标&am…

计算机组成原理的学习笔记(8)-- 指令系统·其一 指令的组成以及数据寻址方式

学习笔记 前言 ​ 本文主要是对于b站尚硅谷的计算机组成原理的学习笔记&#xff0c;仅用于学习交流。 1. 指令 1.1 组成 操作码&#xff08;Opcode&#xff09;&#xff1a;指指令中执行特定操作的部分。地址码&#xff1a;指令中用于指定操作数位置的部分。 1.2 扩展操作…

JavaScript 标准内置对象——Array

1、构造函数 2、静态方法 // 从可迭代或类数组对象创建一个新的浅拷贝的数组实例 // arrayLike 想要转换成数组的类数组或可迭代对象 Array.from(arrayLike, mapFn, thisArg) Array.fromAsync(arrayLike, mapFn, thisArg) // 异步Array.isArray(value) // 判断传递的值是否是一…

IndexOf Apache Web For Liunx索引服务器部署及应用

Apache HTTP Server 是一款广泛使用的开源网页服务器软件,它支持多种协议,包括 HTTP、HTTPS、FTP 等 IndexOf 功能通常指的是在一个目录中自动生成一个索引页面的能力,这个页面会列出该目录下所有的文件和子目录。比如网上经常看到的下图展现的效果,那么接下来我们就讲一下…

【PSINS】EKF、UKF、CKF三个滤波下的组合导航(松组合)对比

该 MATLAB 代码实现了扩展卡尔曼滤波&#xff08;EKF&#xff09;、无迹卡尔曼滤波&#xff08;UKF&#xff09;和无迹卡尔曼滤波的变体&#xff08;CKF&#xff09;的对比&#xff0c;主要用于导航与定位领域&#xff0c;通过处理惯性测量单元&#xff08;IMU&#xff09;和GP…

PPT画图——如何设置导致图片为600dpi

winr&#xff0c;输入regedit打开注册表 按路径找&#xff0c;HKEY_CURRENT_USER\Software\Microsoft\Office\XX.0\PowerPoint\Options&#xff08;xx为版本号&#xff0c;16.0 or 15.0或则其他&#xff09;。名称命名&#xff1a;ExportBitmapResolution 保存即可&#xff0c;…

Linux复习4——shell与文本处理

认识vim编辑器 #基本语法格式&#xff1a; vim 文件名 •如果文件存在&#xff0c;进入编辑状态对其进行编辑 •如果文件不存在&#xff0c;创建文件并进入编辑状态 例&#xff1a; [rootlocalhosttest]# vim practice.txt #Vim 编辑器三种模式&#xff1a; 命令模式&a…

Gmsh有限元网格剖分(Python)---点、直线、平面的移动

Gmsh有限元网格剖分(Python)—点、直线、平面的移动和旋转 最近在学习有限元的网格剖分算法&#xff0c;主要还是要参考老外的开源Gmsh库进行&#xff0c;写一些博客记录下学习过程&#xff0c;方便以后回忆嘞。 Gmsh的官方英文文档可以参考&#xff1a;gmsh.pdf 但咋就说&a…

【Linux】基础I/O -> 如何谈文件与文件系统?

文件的基础理解 空文件也要在磁盘上占据空间。文件 文件内容文件属性。文件操作 对内容的操作 对属性的操作或者是对内容和属性的操作。标定一个文件&#xff0c;必须使用&#xff1a;文件路径 文件名&#xff08;具有唯一性&#xff09;。如果没有指明对应的文件路径&…