NO.85十六届蓝桥杯备战|动态规划-经典线性DP|最长上升子序列|合唱队形|最长公共子序列|编辑距离(C++)
经典线性dp问题有两个:最⻓上升⼦序列(简称:LIS)以及最⻓公共⼦序列(简称:LCS),这两道题⽬的很多⽅⾯都是可以作为经验,运⽤到别的题⽬中。⽐如:解题思路,定义状态表⽰的⽅式,推到状态转移⽅程的技巧等等。
因此,这两道经典问题是⼀定需要掌握的
B3637 最长上升子序列 - 洛谷
- 状态表⽰
dp[i]表⽰:以i 位置元素为结尾的「所有⼦序列」中,最⻓递增⼦序列的⻓度。
最终结果就是整张dp 表⾥⾯的最⼤值。 - 状态转移⽅程:
对于dp[i],我们可以根据「⼦序列的构成⽅式」,进⾏分类讨论:
- ⼦序列⻓度为1 :只能⾃⼰玩了,此时
dp[i] = 1; - ⼦序列⻓度⼤于1 :
a[i]可以跟在前⾯某些数后⾯形成⼦序列。设前⾯的某⼀个数的下标为j,其中 1 ≤ j < i 1 \le j < i 1≤j<i。只要a[j] < a[i],i位置元素跟在j元素后⾯就可以形成递增序列,⻓度为dp[j]+1。
因此,我们仅需找到满⾜要求的最⼤的dp[j] + 1即可。
综上,dp[i] = max(dp[j] + 1, dp[i]),其中1 ≤ j < i && nums[j] < nums[i]。
- 初始化:
不⽤单独初始化,每次填表的时候,先把这个位置的数改成1 即可。 - 填表顺序:
显⽽易⻅,填表顺序「从左往右」
#include <bits/stdc++.h>
using namespace std;const int N = 5010;int n;
int a[N];
int f[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];int ret = 1;for (int i = 1; i <= n; i++){f[i] = 1;for (int j = 1; j < i; j++){if (a[j] < a[i]){f[i] = max(f[i], f[j] + 1);}}ret = max(ret, f[i]);}cout << ret << endl;return 0;
}
最长上升子序列2
利⽤贪⼼+⼆分优化动态规划:
- 我们在考虑最⻓递增⼦序列的⻓度的时候,其实并不关⼼这个序列⻓什么样⼦,我们只是关⼼最后⼀个元素是谁。这样新来⼀个元素之后,我们就可以判断是否可以拼接到它的后⾯。
- 因此,我们可以创建⼀个数组,统计⻓度为 x 的递增⼦序列中,最后⼀个元素是谁。为了尽可能的让这个序列更⻓,我们仅需统计⻓度为 x 的所有递增序列中最后⼀个元素的「最⼩值」。
- 统计的过程中发现,数组中的数呈现「递增」趋势,因此可以使⽤「⼆分」来查找插⼊位置
#include <bits/stdc++.h>
using namespace std;const int N = 1e5 + 10;int n;
int a[N];
int f[N], len;int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= n; i++){if (len == 0 || a[i] > f[len]) f[++len] = a[i];else{//二分插入位置int l = 1, r = len;while (l < r){int mid = (l + r) / 2;if (f[mid] >= a[i]) r = mid;else l = mid + 1;}f[l] = a[i];}}cout << len << endl;return 0;
}
P1091 [NOIP 2004 提高组] 合唱队形 - 洛谷
对于每⼀个位置i ,计算:
- 从左往右看:以i 为结尾的最⻓上升⼦序列
f[i]; - 从右往左看:以i 为结尾的最⻓上升⼦序列
g[i];
最终结果就是所有f[i] + g[i] - 1⾥⾯的最⼤值
#include <bits/stdc++.h>
using namespace std;const int N = 110;int n;
int a[N];
int f[N], g[N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for(int i = 1; i <= n; i++) cin >> a[i];// 从左往右for(int i = 1; i <= n; i++){f[i] = 1;for(int j = 1; j < i; j++){if(a[j] < a[i]){f[i] = max(f[i], f[j] + 1);}}}// 从右往左for(int i = n; i >= 1; i--){g[i] = 1;for(int j = n; j > i; j--){if(a[j] < a[i]){g[i] = max(g[i], g[j] + 1);}}}int ret = 0;for(int i = 1; i <= n; i++){ret = max(ret, f[i] + g[i] - 1);}cout << n - ret << endl;return 0;
}
牛可乐和最长公共子序列
- 状态表⽰:
dp[i][j]表⽰:s1的[1,i]区间以及s2的[1,j]区间内的所有的⼦序列中,最⻓公共⼦序列的
⻓度。
那么dp[n][m]就是我们要的结果。 - 状态转移⽅程:
对于dp[i][j],我们可以根据s1[i]与s2[j]的字符分情况讨论:
a. 两个字符相同s1[i] = s2[j]:那么最⻓公共⼦序列就在s1的[1, i - 1]以及s2的[1, j - 1]区间上找到⼀个最⻓的,然后再加上s1[i]即可。因此dp[i][j] = dp[i - 1][j - 1] + 1;
b. 两个字符不同s1[i] != s2[j]:那么最⻓公共⼦序列⼀定不会同时以s1[i]和s2[j]结尾。那么我们找最⻓公共⼦序列时,有下⾯三种策略:
- 去s1 的
[1, i - 1]以及s2的[1, j]区间内找:此时最⼤⻓度为dp[i - 1][j]; - 去s1 的
[1, i]以及s2 的[1, j - 1]区间内找:此时最⼤⻓度为dp[i][j - 1]; - 去s1 的
[1, i - 1]以及s2 的[1, j - 1]区间内找:此时最⼤⻓度为dp[i - 1][j - 1]
我们要三者的最⼤值即可。但是我们仔细观察会发现,第三种包含在第⼀种和第⼆种情况⾥⾯,但是我们求的是最⼤值,并不影响最终结果。因此只需求前两种情况下的最⼤值即可。
综上,状态转移⽅程为:
if(s1[i] = s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
if(s1[i] != s2[j]) dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])。
- 初始化:
直接填表即可。 - 填表顺序:
根据「状态转移⽅程」得:从上往下填写每⼀⾏,每⼀⾏从左往右
#include <bits/stdc++.h>
using namespace std;const int N = 5010;string s, t;
int f[N][N];int main()
{ios::sync_with_stdio(false);cin.tie(0);while (cin >> s >> t){int n = s.size(), m = t.size();for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){if (s[i - 1] == t[j - 1]) f[i][j] = f[i-1][j-1] + 1;else f[i][j] = max(f[i-1][j], f[i][j-1]);}}cout << f[n][m] << endl;}return 0;
}
P2758 编辑距离 - 洛谷
两个字符串之间的dp 问题,与最⻓公共⼦序列的分析⽅式类似。
- 状态表⽰:
dp[i][j]表⽰:字符串A 中[1, i]区间与字符串B 中[1, j]区间内的编辑距离。
那么dp[n][m]就是我们要的结果 - 状态转移⽅程:
对于dp[i][j],我们可以根据A[i]与B[j]的字符分情况讨论:
a. 两个字符相同A[i] = B[j]:那么dp[i][j]就是A的[1, i - 1]以及B的[1, j - 1]区间内编辑距离dp[i][j] = dp[i - 1][j - 1],因此;
b. 两个字符不同A[i] != B[j]:那么对于A 字符串,我们可以进⾏下⾯三种操作:
- 删掉
A[i]:此时dp[i][j]就是A的[1, i - 1]以及B的[1, j]区间内的编辑距离,因此dp[i][j] = dp[i - 1][j] + 1 - 插⼊⼀个字符:在字符串A的后⾯插⼊⼀个
B[j],此时的dp[i][j]就是A的[1, i]以及B的[1, j - 1]区间内的编辑距离,因此dp[i][j] = dp[i][j - 1] + 1; - 将
A[i]替换成B[j]:此时的dp[i][j]就是A的[1, i - 1]以及B的[1, j - 1]区间内的编辑距离,因此dp[i][j] = dp[i - 1][j - 1] + 1。
我们要三者的最⼩值即可。
- 初始化:
需要注意,当i,j等于0的时候,这些状态也是有意义的。我们可以全部删除,或者全部插⼊让
两者相同。
因此需要初始化第⼀⾏dp[0][j] = j (1 ≤ j ≤ m),第⼀列dp[i][0] = i (1 ≤ i ≤ n)。 - 填表顺序:
初始化完之后,从[1, 1]位置开始从上往下每⼀⾏,每⼀⾏从左往右填表即可
#include <bits/stdc++.h>
using namespace std;const int N = 2010;string a, b;
int n, m;
int f[N][N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> a >> b;n = a.size(); m = b.size();a = " " + a; b = " " + b;//初始化for (int i = 1; i <= n; i++) f[i][0] = i;for (int j = 1; j <= m; j++) f[0][j] = j;for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){if (a[i] == b[j]) f[i][j] = f[i-1][j-1];else f[i][j] = min(min(f[i-1][j], f[i-1][j-1]), f[i][j-1]) + 1;}}cout << f[n][m] << endl;return 0;
}
相关文章:
NO.85十六届蓝桥杯备战|动态规划-经典线性DP|最长上升子序列|合唱队形|最长公共子序列|编辑距离(C++)
经典线性dp问题有两个:最⻓上升⼦序列(简称:LIS)以及最⻓公共⼦序列(简称:LCS),这两道题⽬的很多⽅⾯都是可以作为经验,运⽤到别的题⽬中。⽐如:解题思路&…...
0410 | 软考高项笔记:项目管理概述
以下是不同组织结构中项目经理的角色、工作特点以及快速记忆的方法: 不同组织结构中项目经理的角色和工作特点 组织结构项目经理的角色工作特点职能型组织项目协调者、辅助管理者权力有限,主要负责协调部门间的工作,项目成员向部门经理汇报…...
Vue3的Composition API与React Hooks有什么异同?
Vue3的一个重大更新点就是支持Composition API,而且也被业界称为hooks,那么Vue3的“Hooks”与React的Hooks有这么区别呢? 一、核心相似点 1. 逻辑复用与代码组织 都解决了传统类组件或选项式 API 中逻辑分散的问题,允许将相关逻…...
LangChain4j(1):初步认识Java 集成 LLM 的技术架构
LangChain 作为构建具备 LLM 能力应用的框架,虽在 Python 领域大放异彩,但 Java 开发者却只能望洋兴叹。LangChain4j 正是为解决这一困境而诞生,它旨在借助 LLM 的强大效能,增强 Java 应用,简化 LLM 功能在Java应用中的…...
JDK 21 的新特性有哪些?带你全面解读 Java 的未来
引言:从 JDK 21 看 Java 的进化之路 Java 是一门历久弥新的语言,每一次版本更新都在强化它的生态体系。2023 年发布的 JDK 21,作为长期支持版本(LTS),带来了许多令人兴奋的新特性。不论你是开发者、架构师…...
【C++算法】53.链表_重排链表
文章目录 题目链接:题目描述:解法C 算法代码: 题目链接: 143. 重排链表 题目描述: 解法 模拟 找到链表的中间节点 快慢双指针 把后面的部分逆序 双指针,三指针,头插法 合并两个链表 合并两个有…...
多卡分布式训练:torchrun --nproc_per_node=5
多卡分布式训练:torchrun --nproc_per_node=5 1. torchrun 实现规则 torchrun 是 PyTorch 提供的用于启动分布式训练作业的实用工具,它基于 torch.distributed 包,核心目标是简化多进程分布式训练的启动和管理。以下是其主要实现规则: 进程启动 多进程创建:torchrun 会…...
系统架构设计师之系统设计模块笔记
一、系统设计概述 定义与目标 系统设计是根据系统分析结果,制定系统构建蓝图的过程,核心目标是合理分配功能需求、优化资源使用、确保系统高内聚低耦合,并满足性能、安全、可扩展等非功能需求。主要内容 概要设计:将功能需求分配…...
Elasticsearch:加快 HNSW 图的合并速度
作者:来自 Elastic Thomas Veasey 及 Mayya Sharipova 过去,我们曾讨论过搜索多个 HNSW 图时所面临的一些挑战,以及我们是如何缓解这些问题的。当时,我们也提到了一些计划中的改进措施。本文正是这项工作的成果汇总。 你可能会问…...
图片中文字无法正确显示的解决方案
图片中文字无法正确显示的解决方案 问题描述 在 Linux 系统中生成图片时,图片中的文字(如中文)未能正确显示,可能表现为乱码或空白。这通常是由于系统缺少对应的字体文件(如宋体/SimSun),或者…...
数据结构:通俗解释AOE 网中事件的最早发生时间和最迟发生时间
1. 事件的最早发生时间 在 AOE 网(Activity On Edge Network,边表示活动的网络)中,事件的最早发生时间指从源点(起点)到该事件结点的最长路径长度(即所需时间)。它决定了所有以该事…...
C# 看门狗策略实现
using System; using System.Threading;public class Watchdog {private Timer _timer;private volatile bool _isTaskAlive;private readonly object _lock new object();private const int CheckInterval 5000; // 5秒检测一次private const int TimeoutThreshold 10000; …...
在 openEuler 24.03 (LTS) 操作系统上添加 ollama 作为系统服务的步骤
以下是在 openEuler 操作系统上添加 ollama 作为系统服务的步骤: 创建 systemd 服务文件 sudo vi /etc/systemd/system/ollama.service将以下内容写入服务文件(按需修改参数): [Unit] DescriptionOllama Service Afternetwork.…...
Elasticsearch中的基本全文搜索和过滤
Elasticsearch中的基本全文搜索和过滤 知识点参考: https://www.elastic.co/guide/en/elasticsearch/reference/current/full-text-filter-tutorial.html#full-text-filter-tutorial-range-query 1. 索引设计与映射 多字段类型(Multi-Fields) ÿ…...
基于VSCode的Qt开发‘#include ui_test.h’报错没有该文件
笔者在基于VSCode进行Qt开发时,test.ui文件是在Qt软件中绘制的,导致本项目无法使用这个ui文件,报错如标题。事实上,本工程中也确实没有生成这个头文件。出现这个错误的原因是ui文件没有被编译为c头文件。 要生成 ui_test.h 文件&…...
Python常用排序算法
1. 冒泡排序 冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,比较相邻的元素,如果他们的顺序错误就交换他们。 def bubble_sort(arr):# 遍历所有数组元素for i in range(len(arr)):# 最后i个元素是已经排序好的for j in range(0, …...
ISP--Demosaicking
文章目录 前言算法解释简单的线性插值代码实现 色差法和色比法基于方向加权的方法RB缺失的G通道的插值RB缺失的BR的插值G缺失的BR的插值代码实现 基于边缘检测的方法计算缺失的G计算缺失的RB值/计算缺失的G值 前言 人眼之所以有能感受到自然界的颜色,是因为人眼的感…...
国标GB28181协议EasyCVR视频融合平台:5G时代远程监控赋能通信基站安全管理
一、背景介绍 随着移动通信行业的迅速发展,无人值守的通信基站建设规模不断扩大。这些基站大多建于偏远地区,周边人迹罕至、交通不便,给日常的维护带来了极大挑战。其中,位于空旷地带的基站设备,如空调、蓄电池等&…...
vue watch 和 watchEffect的区别和用法
在 Vue.js 里,watch 和 watchEffect 都用于响应式地追踪数据变化并执行相应操作,不过它们在使用方式、应用场景等方面存在差异。 1. watch watch 是 Vue 提供的一个选项,用于监听特定数据的变化。当监听的数据发生变化时,会触发…...
SQL 不走索引的常见情况
在 SQL 查询中,即使表上有索引,某些情况下数据库优化器也可能决定不使用索引。以下是常见的不走索引的情况: 1. 使用否定操作符 NOT IN ! 或 <> NOT EXISTS NOT LIKE 2. 对索引列使用函数或运算 -- 不走索引 SELECT * FROM user…...
git配置 gitcode -- windows 系统
版本 $ git --version git version 2.49.0.windows.1检查现有的 SSH 密钥 打开git-bash终端,执行以下命令查看是否已经生成过 SSH 密钥: ls -al ~/.ssh如果看到类似 id_rsa 和 id_rsa.pub(或者其他命名的密钥对)文件࿰…...
基于Kubeadm实现K8S集群扩缩容指南
一、集群缩容操作流程 1.1 缩容核心步骤 驱逐节点上的Pod 执行kubectl drain命令驱逐节点上的Pod,并忽略DaemonSet管理的Pod: kubectl drain <节点名> --ignore-daemonsets # 示例:驱逐worker233节点 kubectl drain worker233 --ignor…...
模拟-与-现实协同训练:基于视觉机器人操控的简单方法
25年3月来自 UT Austin、Nvidia、UC Berkeley 和纽约大学的论文“Sim-and-Real Co-Training: A Simple Recipe for Vision-Based Robotic Manipulation”。 大型现实世界机器人数据集在训练通才机器人模型方面拥有巨大潜力,但扩展现实世界人类数据收集既耗时又耗资…...
WRS-PHM电机智能安康系统:为浙江某橡胶厂构筑坚实的生产防线
以行业工况为背景 一、顾客工厂的背景 浙江某橡胶厂以电机为中心生产设备必须连续平稳运行。但由于缺乏有效的故障预警体系,电机故障就像潜伏着的“不定时炸弹”,不但不时地造成生产流程的中断,也使对生产进行管理异常艰难,对持续安全生产提…...
将 CrewAI 与 Elasticsearch 结合使用
作者:来自 Elastic Jeffrey Rengifo 学习如何使用 CrewAI 为你的代理团队创建一个 Elasticsearch 代理,并执行市场调研任务。 CrewAI 是一个用于编排代理的框架,它通过角色扮演的方式让多个代理协同完成复杂任务。 如果你想了解更多关于代理…...
wait 和notify ,notifyAll,sleep
wait 使线程进入阻塞状态,释放CPU,以及锁 sleep 使线程进入睡眠状态,sleep方法不会释放CPU资源和锁资源,而是让出CPU的使用权。操作系统会将CPU分配给其他就绪线程,但当前线程依然存在,不会释放其占用的…...
ECMAScript 6 新特性(二)
ECMAScript 6 新特性(二) ECMAScript 6 新特性(一) ECMAScript 6 新特性(二)(本文) ECMAScript 7~10 新特性 1. 生成器 生成器函数是 ES6 提供的一种解决异步编程方案,一…...
SpringBoot接口覆盖上一次调用的实现方案
调用springboot接口时,如何实现覆盖上一次调用 Spring Boot 接口覆盖上一次调用的实现方案 以下是多种实现覆盖上一次接口调用的方案,适用于不同场景。 方案一:同步锁控制(单机环境) 适用场景:单实例…...
Spring 的 IoC 和 DI 详解:从零开始理解与实践
Spring 的 IoC和 DI 详解:从零开始理解与实践 一、IoC(控制反转) 1、什么是 IoC? IoC 是一种设计思想,它的核心是将对象的创建和管理权从开发者手中转移到外部容器(如 Spring 容器)。通过这种…...
Python Cookbook-5.12 检查序列的成员
任务 你需要对一个列表执行很频繁的成员资格检査。而in操作符的 O(n)时间复杂度对性能的影响很大,你也不能将序列转化为一个字典或者集合,因为你还需要保留原序列的元素顺序。 解决方案 假设需要给列表添加一个在该列表中不存在的元素。一个可行的方法…...
