最长子序列

news/2024/10/11 8:27:06

例题

两个字符串的最长公共子序列其实可以理解为一个二维dp

如图,每个格子都代表的是当以当前下标为结尾的时候所能构成的最长序列,每个格子都有三种转移方式,不要a的末尾,不要b的末尾和两个都不要,当a[i]b[j]的时候,此时,a[i]b[j],就是从箭头所指的方位转移了过来,也就是两个字符串的结尾都不要,相当于直接从dp[i-1][j-1]的情况加了1,这也是下面为什么max()只需要比dp[i-1][j]和dp[i][j-1]。因此,我们就能得出当a[i]b[j]的情况代码,dp[i][j]=dp[i-1][j-1]+1;而当不相等时,则要选取其中一种情况,要么不要a的末尾,要么不要b的末尾,我们由此便可得出dp[i][j]=max(dp[i-1][j],dp[i][j-1]);此外,我们还要算个数,方案数其实就如同上面的情况一般,不同的是,因为dp[i-1][j]和dp[i][j-1]都是经过了dp[i-1],[j-1]转移过来,所以当a[i]!=b[j]&&dp[i][j]dp[i-1][j-1],dp[i][j]多加了一次dp[i-1][j-1]。
所以,代码如下

点击查看代码
#include <iostream>      // 输入输出流
#include <iomanip>       // 输入输出格式控制
#include <fstream>       // 文件输入输出流
#include <sstream>       // 字符串输入输出流
#include <cmath>         // 数学函数
#include <string>        // 字符串操作
#include <vector>        // 动态数组容器
#include <queue>         // 队列容器
#include <stack>         // 栈容器
#include <set>           // 集合容器
#include <map>           // 映射容器
#include <unordered_set> // 无序集合容器
#include <unordered_map> // 无序映射容器
#include <algorithm>     // 算法
#include <bitset>        // 位集容器
#include <stdio.h>       // 标准输入输出using namespace std;
typedef long long ll;
int dp[1001][1001];
ll cnt[1001][1001];
const int mod = 100000000;
string a, b;
void print(int n, int m)
{if (n == 0 || m == 0)return;if (dp[n][m] == dp[n - 1][m - 1] + 1){print(n - 1, m - 1);cout << a[n];}else if (dp[n][m] == dp[n - 1][m])print(n - 1, m);elseprint(n, m - 1);
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout << fixed << setprecision(12);cin >> a >> b;int n = a.size(), m = b.size();a = " " + a;b = " " + b;for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){if (a[i] == b[j]){dp[i][j] = dp[i - 1][j - 1] + 1;}else{dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);}}}cout << dp[n][m]<< endl;// // 个数for (int i = 0; i <= m; i++){cnt[0][i] = 1;}for (int i = 0; i <= n; i++){cnt[i][0] = 1;}for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){ll u = cnt[i][j];if (a[i] == b[j] && dp[i][j] == dp[i - 1][j - 1] + 1)u = (u + cnt[i - 1][j - 1]) % mod;if (dp[i][j] == dp[i - 1][j])u = (u + cnt[i - 1][j]) % mod;if (dp[i][j] == dp[i][j - 1])u = (u + cnt[i][j - 1]) % mod;if (a[i] != b[j] && dp[i][j] == dp[i - 1][j - 1])u = ((u - cnt[i - 1][j - 1]) % mod + mod) % mod;cnt[i][j] = u;}}cout << cnt[n][m] << endl;// 最长字串// print(n, m);return 0;
}

这个代码也有很大的限制,在空间上有很大限制,所以可以用滚动数组来优化一下

点击查看代码
#include <iostream>      // 输入输出流
#include <iomanip>       // 输入输出格式控制
#include <fstream>       // 文件输入输出流
#include <sstream>       // 字符串输入输出流
#include <cmath>         // 数学函数
#include <string>        // 字符串操作
#include <vector>        // 动态数组容器
#include <queue>         // 队列容器
#include <stack>         // 栈容器
#include <set>           // 集合容器
#include <map>           // 映射容器
#include <unordered_set> // 无序集合容器
#include <unordered_map> // 无序映射容器
#include <algorithm>     // 算法
#include <bitset>        // 位集容器
#include <stdio.h>       // 标准输入输出using namespace std;
typedef long long ll;
int dp[2][10001];
ll cnt[2][10001];
const int mod = 100000000;
string a, b;int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout << fixed << setprecision(12);cin >> a >> b;int n = a.size(), m = b.size();a = " " + a;b = " " + b;for (int i = 0; i <= m; i++){cnt[0][i] = 1;}cnt[1][0] = 1;for (int i = 1; i <= n; i++){int now = i & 1, pre = now ^ 1;//&和^的结果是反过来的,所以pre就可以代表上一次的状态for (int j = 1; j <= m; j++){dp[now][j] = max(dp[pre][j], dp[now][j - 1]);if (a[i] == b[j]){dp[now][j] = max(dp[now][j], dp[pre][j - 1] + 1);}cnt[now][j] = 0;//滚动到当前的状态,cnt清零防止被上次的影响if (a[i] == b[j] && dp[now][j] == dp[pre][j - 1] + 1){cnt[now][j] = (cnt[now][j] + cnt[pre][j - 1]) % mod;}if (dp[now][j] == dp[pre][j]){cnt[now][j] = (cnt[now][j] + cnt[pre][j]) % mod;}if (dp[now][j] == dp[now][j - 1]){cnt[now][j] = (cnt[now][j] + cnt[now][j - 1]) % mod;}if (a[i] != b[j] && dp[now][j] == dp[pre][j - 1])//此时的dp[now][j]被dp[pre][j-1]影响了两次。{cnt[now][j] = ((cnt[now][j] - cnt[pre][j - 1]) + mod) % mod;}}}cout << dp[n & 1][m] - 1 << endl;cout << cnt[n & 1][m] << endl;return 0;
}

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

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

相关文章

.NET周刊【10月第1期 2024-10-06】

国内文章 基于DPAPI+RDP技术实现本地打开远程程序,并映射到本地机器桌面上 https://www.cnblogs.com/weskynet/p/18445584 该教程讲述如何使用RemoteShadowApp进行远程设置和程序启动。使用工具需要VS2022、.NET 8和WPF,并通过DPAPI加密数据。教程展示了利用该程序自动更新远…

政策应该是政策出台框架下的政策

管理出台政策的政策,而且政策应该是有层级结构的,不是像现在这样,随意的出,经济快被刺激死了相信世界是平的 谨记四个字“修身养性” 大江东去浪淘尽英雄,再牛B的人物最后也是一掊土 向善不是目的,而是抚慰心灵,更多的感受幸福,感谢别人给你行善的机会 相信老子的话:万…

VMware vCenter Server 6.7U3v 发布下载 - ESXi 集中管理软件

VMware vCenter Server 6.7U3v 发布下载 - ESXi 集中管理软件VMware vCenter Server 6.7U3v 发布下载 - ESXi 集中管理软件 集中式控制 vSphere 环境 请访问原文链接:https://sysin.org/blog/vmware-vcenter-6-7/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org…

读数据工程之道:设计和构建健壮的数据系统05底层设计(上)

底层设计1. 主要底层设计 1.1. 以前的数据工程周期只关注技术层,而工具和实践的持续抽象和简化已经改变了这一重点 1.2. 数据工程现在包含的不仅仅是工具和技术1.2.1. 该领域现在正在向价值链上游移动,将数据管理和成本优化等传统企业实践与DataOps等新实践相结合1.3. 底层设…

32. 基本数据类型、约束条件

1. 基本数据类型 1.1 整型整数类型 所占字节 所占位数无符号数的取值范围 unsigned有符号数的取值范围TINYINT 1 8 0~255 -128~127SMALLINT 2 16 0~65535 -32768~32767MEDIUMINT 3 24 0~16777215 -8388608~8388607INT 4 32 0~4294967295 -2147483648~2147483647BIGINT 8 64 0~1…

2024.10.10 高代习题课

因为我觉得有点难,所以写之。只能说有些人的智商水平就这样了,不是说来到一个平均智商更高的地方就能解决的。 练习 1: 因式分解下面行列式的值: \[\begin{vmatrix} \ 0 & x & y & z\ \\ \ x & 0 & z & y\ \\ \ y & z & 0 & x\ \\ \ z…

20222404 2024-2025-1 《网络与系统攻防技术》实验一实验报告

姓名:张嘉月 学号:20222404 实验日期:2024/09/29 — 2024/10/09 实验名称:缓冲区溢出和shellcode 指导教师:王志强 一、实验内容任务一:手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数。 任务二:利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回…