#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
char a[N],b[M];
int main(int argc,char const* args[] ){
int n,m;
std::ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m;
cin>>a>>b;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i-1]==b[j-1]){
f[i][j]=f[i-1][j-1]+1;
}else{
f[i][j]=std::max(f[i-1][j],f[i][j-1]);
}
}
}
cout<<f[n][m]<<endl;
return 0;
}
这段代码的数组f[i][j]表示序列a[0…i-1]和b[0…j-1]的最长公共子序列长度。
对于每个位置 (i, j),根据最后一个元素 a[i-1]和b[j-1],可以分为以下几种情况:
- 如果a[i-1]等于b[j-1],那么a[i-1]和b[j-1]一定在最长公共子序列中,此时可以在a[0…i-2]和b[0…j-2]的最长公共子序列的基础上加上 a[i-1](或者b[j-1]),所以有 f[i][j] = f[i-1][j-1] + 1。
- 如果a[i-1]不等于b[j-1],那么a[i-1]和b[j-1]不能同时在最长公共子序列中。根据公共子序列的定义,可能出现两种情况:
- a[i-1]在最长公共子序列中,但b[j-1]不在,此时可以将b[j-1]从序列b中删除,即比较a[0…i-1]和b[0…j-2]的最长公共子序列,所以有 f[i][j] = f[i][j-1]。
- b[j-1]在最长公共子序列中,但a[i-1]不在,此时可以将a[i-1]从序列a中删除,即比较a[0…i-2]和b[0…j-1]的最长公共子序列,所以有 f[i][j] = f[i-1][j]。
综上所述,根据不同的情况,可以使用状态转移方程来计算f[i][j]:
f[i][j] =
- f[i-1][j-1] + 1,当a[i-1]等于b[j-1];
- max(f[i-1][j], f[i][j-1]),当a[i-1]不等于b[j-1]。
最后,输出f[n][m],即为两个字符串的最长公共子序列的长度。
#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
int8_t p[N][M];
char a[N],b[M],s[N];
int main(int argc,char const* args[] ){
int n,m;
std::ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m;
cin>>a>>b;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i-1]==b[j-1]){
f[i][j]=f[i-1][j-1]+1;
}else if(f[i-1][j]>f[i][j-1]){
f[i][j]=f[i-1][j];
p[i][j]=1;
}else{
f[i][j]=f[i][j-1];
p[i][j]=-1;
}
}
}
int i=n,j=m,k=f[n][m];
cout<<k<<endl;
while(i>0&&j>0){
switch(p[i][j]){
case 0: --i;--j;s[--k]=a[i];break;
case 1: --i;break;
default:--j
}
}
cout<<s;
return 0;
}
这段代码实现了最长公共子序列(Longest Common Subsequence)问题的动态规划算法。给定两个字符串a和b,程序计算出它们的最长公共子序列,并输出该子序列的长度和内容。
具体而言,代码中使用一个二维数组f来存储最长公共子序列的长度,数组p用于回溯构建子序列。f[i][j]表示字符串a的前i个字符和字符串b的前j个字符的最长公共子序列的长度。p[i][j]表示从f[i][j]的值推导出来的最长公共子序列的字符位置关系,其中0表示字符a[i]和b[j]都包含在最长公共子序列中,1表示字符a[i]包含在最长公共子序列中,-1表示字符b[j]包含在最长公共子序列中。
代码通过遍历字符串a和字符串b的每个字符,根据字符的匹配关系更新f和p数组的值。最后,利用p数组回溯构建最长公共子序列,并输出结果。
#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
//int8_t p[N][M];
char a[N],b[M],s[N];
int main(int argc,char const* args[] ){
int n,m;
std::ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>n>>m;
cin>>a>>b;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i-1]==b[j-1]){
f[i][j]=f[i-1][j-1]+1;
}else if(f[i-1][j]>f[i][j-1]){
f[i][j]=f[i-1][j];
// p[i][j]=1;
}else{
f[i][j]=f[i][j-1];
// p[i][j]=-1;
}
}
}
int i=n,j=m,k=f[n][m];
cout<<k<<endl;
while(i>0&&j>0){
// switch(p[i][j]){
// case 0: --i;--j;s[--k]=a[i];break;
// case 1: --i;break;
// default:--j;
// }
if(a[i-1]==b[j-1]){
--j;s[--k]=a[--i];
}else if(f[i-1][j]>f[i][j-1]){
--i;
}else{
--j;
}
}
cout<<s;
return 0;
}
这段代码实现了最长公共子序列(Longest Common Subsequence)问题的动态规划算法,和前一个版本不同的是这里不再使用p数组来回溯构建最长公共子序列,而是直接利用条件语句。
具体而言,代码中使用一个二维数组f来存储最长公共子序列的长度。f[i][j]表示字符串a的前i个字符和字符串b的前j个字符的最长公共子序列的长度。
程序通过遍历字符串a和字符串b的每个字符,根据字符的匹配关系更新f数组的值。最后,利用条件语句根据当前字符的匹配情况,更新i、j以及s数组的值。最终,输出最长公共子序列的长度和内容。