acwing算法基础之动态规划--线性DP和区间DP

目录

  • 1 基础知识
  • 2 模板
  • 3 工程化

1 基础知识

线性DP:状态转移表达式存在明显的线性关系。
区间DP:与顺序有关,状态与区间有关。

2 模板

3 工程化

题目1:数字三角形。

解题思路:直接DP即可,f[i][j]可以来自f[i-1][j] + a[i][j]f[i-1][j-1] + a[i][j],注意f[i-1][j]不存在的情况(最后一个点)和f[i-1][j-1]不存在的情况(第一个点)。

C++代码如下,

#include <iostream>using namespace std;const int N = 510;
int n;
int a[N][N];
int f[N][N];int main() {cin >> n;for (int i = 0; i < n; ++i) {for (int j = 0; j < i + 1; ++j) {cin >> a[i][j];}}for (int i = 0; i < N; ++i) {for (int j = 0; j < N; ++j) {f[i][j] = -0x3f3f3f3f;}}f[0][0] = a[0][0];for (int i = 1; i < n; ++i) {for (int j = 0; j < i + 1; ++j) {f[i][j] = max(f[i][j], f[i-1][j] + a[i][j]);if (j - 1 >= 0) f[i][j] = max(f[i][j], f[i-1][j-1] + a[i][j]);}}int res = -0x3f3f3f3f;for (int j = 0; j < n; ++j) res = max(res, f[n-1][j]);cout << res << endl;return 0;
}

题目2:最长上升子序列。注意可以连续,比如3 1 2 1 8 5 6,那么它的最长上升子序列为1 2 5 6,长度为4。

解题思路:DP即可。

状态定义,f[i]表示以第 i i i元素结尾的上升子序列的最大长度。

状态转移,有,

  1. 没有上一个元素,即f[i] = 1
  2. 从第 i − 1 i-1 i1个元素转移过来,需要满足a[i-1] < a[i],则f[i-1] + 1
  3. 从第 i − 2 i-2 i2个元素转移过来,需要满足a[i-2] < a[i],则f[i-2] + 1
    ……
  4. 从第 0 0 0个元素转移过来,需要满足a[0] < a[i],则f[0] + 1

C++代码如下,

#include <iostream>using namespace std;const int N = 1010;
int n;
int a[N];
int f[N];int main() {cin >> n;for (int i = 0; i < n; ++i) cin >> a[i];for (int i = 0; i < n; ++i) {f[i] = 1;for (int j = 0; j < i; ++j) {if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1);} }int res = 0;for (int i = 0; i < n; ++i) res = max(res, f[i]);cout << res << endl;return 0;
}

同时输出最长上升子序列,那么此时只需要记住当前状态是从哪一个状态转移过来的,然后逆序输出即可。C++代码如下,

#include <iostream>
#include <algorithm>using namespace std;const int N = 1010;
int n;
int a[N];
int f[N];
int g[N];int main() {cin >> n;for (int i = 0; i < n; ++i) cin >> a[i];for (int i = 0; i < n; ++i) {f[i] = 1;g[i] = -1; //g[i]=-1表示它是子序列的起点for (int j = 0; j < i; ++j) {if (a[j] < a[i]) {if (f[i] < f[j] + 1) {f[i] = f[j] + 1;g[i] = j;//g[i]=j表示状态f[i]是从状态f[j]转移过来的}}} }int res = 0;for (int i = 0; i < n; ++i) {if (f[i] > f[res]) {res = i;}}cout << f[res] << endl;//输出最长子序列的长度vector<int> ans; //最长子序列for (int i = res; i != -1; i = g[i]) {ans.emplace_back(a[i]);}reverse(ans.begin(), ans.end());for (int i = 0; i < ans.size(); ++i) cout << ans[i] << " ";cout << endl;return 0;
}

测试样例,

输入:
7
3 1 2 1 8 5 6
输出:
4
1 2 5 6 

题目3:最长公共子序列,给定字符串a和字符串b,求它们的最长公共子序列。例如acbdabedc,则它们的最长公共子序列为abd,长度为3。

思路:利用DP来求解,由于这里求的是最大长度,因此在状态转移时,可以适当放大,以便可以表示相应转移路径。

状态定义,f[i][j]:从字符串a前i个中选且从字符串b中前j个中选的公共子序列的最大长度。

状态转移,有,

  1. a[i]不在最优公共子序列当中,b[j]不在最优公共子序列当中,则f[i-1][j-1]
  2. a[i]在最优公共子序列当中,b[j]不在最优公共子序列当中,无法表示???,故将其放大,为f[i][j-1]
  3. a[i]不在最优公共子序列当中,b[j]在最优公共子序列当中,无法表示???,故将其放大,为f[i-1][j]
  4. a[i]在最优公共子序列当中,b[j]在最优公共子序列当中,要求a[i]=b[j],则f[i-1][j-1] + 1

进一步思考,由于进行了放大,因此第(2)种情况和第(3)种情况包含了第(1)种情况。因此在代码实现时,可以考虑如下状态转移f[i][j-1]f[i-1][j]f[i-1][j-1] + 1

C++代码如下,

#include <iostream>using namespace std;const int N = 1010;
char a[N], b[N];
int n, m;
int f[N][N];int main() {cin >> n >> m;cin >> a + 1 >> b + 1;for (int i = 1; i <= n; ++i) {for (int j = 1; j <= m; ++j) {f[i][j] = max(f[i-1][j], f[i][j-1]);if (a[i] == b[j]) f[i][j] = max(f[i][j], f[i-1][j-1] + 1);}}cout << f[n][m] << endl;return 0;
}

题目4:合并相邻石子的最小代价。例如1 3 5 2,合并前两堆石子13的代价是4,得到4 5 2

解题思路:区间合并类DP,状态定义围绕着区间,然后怎么层层递进计算状态,比较考验。答案是枚举区间长度来计算。

状态定义,f[i][j]:合并第i~j堆石子的最小代价。

状态转移,有,

  1. 最后一次合并为[i,i]和[i+1,j]这两个区间合并,即f[i][i] + f[i + 1][j] + s[j] - s[i - 1],其中s[i]表示前缀和。
  2. 最后一次合并为[i,i+1]和[i+2,j]这两个区间合并,即f[i][i + 1] + f[i + 2][j] + s[j] - s[i - 1]
  3. 最后一次合并为[i,i+2]和[i+3,j]这两个区间合并,即f[i][i + 2] + f[i + 3][j] + s[j] - s[i - 1]
    ……
  4. 最后一次合并为[i,j-1]和[j,j]这两个区间合并,即f[i][j - 1] + f[j][j] + s[j] - s[i - 1]

初始化,f[i][i]=0,然后其余初始化为正无穷大,比如1e9

最终答案为,f[1][n]

注意状态的遍历,是通过区间长度从1到n实现的。

C++代码如下,

#include <iostream>using namespace std;const int N = 310;
int a[N];
int s[N];
int f[N][N];
int n;int main() {cin >> n;for (int i = 1; i <= n; ++i) cin >> a[i];for (int i = 1; i <= n; ++i) s[i] += s[i-1] + a[i];for (int len = 2; len <= n; ++len) {//枚举左端点for (int i = 0; i + len - 1 <= n; ++i) {int l = i, r = i + len - 1;f[l][r] = 1e9;for (int k = l; k < r; ++k) {f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);}}}cout << f[1][n] << endl;return 0;
}

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

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

相关文章

ABAP算法 模拟退火

模拟退火算法 算法原理及概念本文仅结合实现过程做简述 模拟退火算法是一种解决优化问题的算法。通过模拟固体退火过程中的原子热运动来寻找全局最优解。在求解复杂问题时&#xff0c;模拟退火算法可以跳出局部最优解获取全局最优解。 模拟退火算法包含退火过程和Metropolis算法…

NC56 XML 报文校验出错一例

好好的上线了、下午开完会告诉我有个凭证没法传入 NC 了。 请求报文如下&#xff1a; <?xml version"1.0" encodingUTF-8?> <ufinterface roottag"voucher" billtype"gl" replace"Y" receiver"10108" sender&q…

舞蹈店管理系统服务预约会员小程序效果如何

舞蹈的作用很广&#xff0c;也有大量求学者&#xff0c;每个城市也有大小各异的舞蹈品牌店&#xff0c;他们承接商演、也会教学员、宣传拓展生意等&#xff0c;因此近些年来&#xff0c;随着互联网深入及短视频&#xff0c;舞蹈业市场规模也在增加。 而在门店经营中&#xff0…

Java中关于ArrayList集合的练习题

目录 题目内容​编辑 完整源码 题目内容 根据下图所示数据&#xff0c;定义学生类Student&#xff0c;设置对应的字段并进行封装在Test中&#xff0c;定义ArrayList集合 ,将上述学生对象实例化&#xff0c;并放入集合&#xff0c;定义方法t1&#xff0c;参数为学生类集合&am…

js数组map()的用法

JavaScript Array map() 方法 先说说这个方法浏览器的支持&#xff1a; 支持五大主流的浏览器&#xff0c; 特别注意&#xff1a;IE 9 以下的浏览器不支持&#xff0c;只支持IE 9以上的版本的浏览器 特别注意&#xff1a;IE 9 以下的浏览器不支持&#xff0c;只支持IE 9以上的…

从零开始的c语言日记day37——数组指针练习

一、 取地址数组储存在了*p里&#xff0c;里面储存的是整个数组的地址但本质也是第一个元素的地址解引用后1为4个字节所以就可以打印数组了。但一般不用这种方法 这样更方便一些 打印多维数组 如果不用这样传参&#xff0c;用指针传参怎么做呢&#xff1f; Main里函数的arr表示…

QT基础实践之简易计算器

文章目录 简易计算器源码分享演示图第一步 界面设计第二步 设置槽第三步 计算功能实现 简易计算器 源码分享 链接&#xff1a;https://pan.baidu.com/s/1Jn5fJLYOZUq77eNJ916Kig 提取码&#xff1a;qwer 演示图 第一步 界面设计 这里直接用了ui界面&#xff0c;如果想要自己…

TiDB 7.x 源码编译之 TiDB Server 篇,及新特性详解

本文将介绍如何编译 TiDB Server 源码。以及阐释 TiDB Server 7.x 的部分新特性。 TiDB v7.5.0 LTS 计划于 2023 年 11 月正式 Release&#xff0c;目前代码虽未冻结&#xff0c;但已经可以看到 Alpha 版本的 Code 了&#xff0c;本文代码将以 v7.5.0-alpha 为基准。 TiDB Se…

系统管理精要:深度探索 Linux 监控与管理利器

前言 系统管理在 Linux 运维中扮演着至关重要的角色&#xff0c;涵盖了系统的配置、监控和维护。了解这些方面的工具和技术对于确保系统稳定运行至关重要。本文将着重介绍系统管理的关键部分&#xff0c;包括配置系统、监控系统状态和系统的日常维护&#xff0c;并以 top 和 vm…

【协议设计与实现】Linux环境下,如何从0开始设计并实现一个网络协议之一——需要考虑的因素

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;TCP/IP协议&…

filebeat 日志收集工具

elk&#xff1a;filebeat日志收集工具和logstash相同。 filebeat是一个轻量级的日志收集工具&#xff0c;所使用的系统资源比logstash部署和启动时使用的资源要小的多。 filebeat可以运行在非Java环境。他可以代理logtash在非java环境上收集日志。 filebeat无法实现数据的过…

设计师福利!2024在线图标设计网站推荐,不容错过的宝藏!

在当今竞争激烈的商业环境中&#xff0c;公司或个人品牌的视觉识别元素已经成为区分你和竞争对手的关键因素之一。一个独特而引人注目的标志可以深深扎根于人们的心中&#xff0c;并在消费者心中建立一个强烈的品牌印象。如果你正在寻找合适的工具来创建或改进你的标志&#xf…

WIFI HaLow技术引领智能互联,打破通信限制

在过去十年里&#xff0c;WIFI技术已在家庭和企业中建立起了庞大的网络&#xff0c;连接了数十亿智能互联设备&#xff0c;促进了信息的迅速传递。然而&#xff0c;当前的WIFI标准存在一些挑战&#xff0c;包括协议范围的限制和整体功能的受限&#xff0c;导致在较远距离进行通…

02-鸿蒙学习之4.0todoList练习

02-鸿蒙学习之4.0todoList练习 代码 /*** 1:组件必须使用Component装饰* 2.Entry 装饰哪个组件&#xff0c;哪个组件就呈现在页面上* 3.被Entry 装饰的入口组件。build&#xff08;&#xff09;必须有且仅有一个根 ** 容器 ** 组件* 其他的自定义组件&#xff0c;build() 中…

C++学习——类和对象(上)

C学习——类和对象 一、面向对象和面向过程的初步认识二、什么是类 一、面向对象和面向过程的初步认识 我们之前学习了C语言&#xff0c;我们知道 ① C语言&#xff1a;C语言是一门面向过程的语言&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函…

Anakki个人网站持续更新中

Anakki-World github&#xff1a; GitHub - Anyuei/anakki 欢迎注册&#xff0c;成为我的盆友

Android Bitmap保存成至手机图片文件,Kotlin

Android Bitmap保存成至手机图片文件&#xff0c;Kotlin fun saveBitmap(name: String?, bm: Bitmap) {val savePath Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()if (!Files.exists(Paths.get(savePath))) {Log.d("保存文…

用通俗的方式讲解Transformer:从Word2Vec、Seq2Seq逐步理解到GPT、BERT

直到今天早上&#xff0c;刷到CSDN一篇讲BERT的文章&#xff0c;号称一文读懂&#xff0c;我读下来之后&#xff0c;假定我是初学者&#xff0c;读不懂。 关于BERT的笔记&#xff0c;其实一两年前就想写了&#xff0c;迟迟没动笔的原因是国内外已经有很多不错的资料&#xff0…

Appium自动化如果出现报错怎么办?这么做确实解决问题

解决通过appium的inspector功能无法启动app的原因 在打开appium-desktop程序&#xff0c;点击inspector功能&#xff0c;填写app的配置信息&#xff0c;启动服务提示如下&#xff1a; 报错信息&#xff1a; An unknown server-side error occurred while processing the com…

【ShardingSphere专题】SpringBoot整合ShardingSphere(一、数据分片入门及实验)

目录 前言阅读对象笔记正文一、ShardingSphere介绍1.1 ShardingSphere-JDBC&#xff1a;代码级别1.2 ShardingSphere-Proxy&#xff1a;应用级别1.3 横向对比图 二、ShardingSphere之——数据分片2.1 基本介绍2.2 分片的形式2.2.1 垂直分片2.2.2 水平分片 2.3 数据分片核心概念…