给定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B 的子序列的字符串长度最长是多少。
输入格式
第一行包含两个整数 N 和 M。
第二行包含一个长度为 N 的字符串,表示字符串 A。
第三行包含一个长度为 M 的字符串,表示字符串 B。
字符串均由小写字母构成。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N,M≤1000
输入样例:
4 5
acbd
abedc
输出样例:
3
纯dp
转态表示:f[i][j]表示从a串前i个选b串前j个选的所有集合
属性:最大值
转态转移:选第i个数,第j个数不选那不就相当于是从a串前i个,b串前j-1个中选个最大值吗:f[i][j]=f[i][j-1];
选第j个数 f[i][j]=f[i-1][j];
选第i个数和第j个数需要满足条件 a[i]==b[j];f[i][j]=f[i-1][j-1]+1;
都不选:f[i][j]=f[i-1][j-1];
#include <iostream>
using namespace std;
const int N = 1010;
int n, m;
char a[N], b[N];
int f[N][N];
int main() {
cin >> n >> m >> a + 1 >> b + 1;
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] + 1;
} else {
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
}
cout << f[n][m] << '\n';
return 0;
}
下面这个代码可以输出最长公共子序列
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
char a[N],b[N];
int c[N][N],f[N][N];
int n,m;
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
for(int j=1;j<=m;j++) cin >> b[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]+1;
c[i][j]=1;//左上
}
else if(f[i-1][j]>f[i][j-1]){
f[i][j]=f[i-1][j];
c[i][j]=2; //上
}
else{
f[i][j]=f[i][j-1];//左;
}
}
}
cout << f[n][m]<<endl;
stack<char>same;
for(int i=n,j=m;j>=1&&i>=1;){
if(c[i][j]==1){
same.push(a[i]);
i--,j--;
}
else if(c[i][j]==2){
i--;
}
else{
j--;
}
}
while(!same.empty()){
cout << same.top();
same.pop();
}
return 0;
}
是怎么输出的呢?
有点麻烦
可以参考这个博客
点我去大佬博客
补充一点
这个图中,圆圈中的是公共部分,路径上非圆圈的是其中一个串有,而另一个没有的;
关于这一点可以去做这个题
反正我是被恶心到了hh
这个题的题解可以参考这里
记忆化搜索
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
char a[N],b[N];
int f[N][N];
bool st[N][N];
int n,m;
int dp(int i,int j){
if(i>n||j>m) return 0;
if(st[i][j]) return f[i][j];
st[i][j]=true;
if(a[i]==b[j]){
f[i][j]=max(f[i][j],dp(i+1,j+1)+1);
}
f[i][j]=max(f[i][j],max(dp(i+1,j),dp(i,j+1)));
return f[i][j];
}
int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
}
for(int i=1;i<=m;i++){
cin >> b[i];
}
cout << dp(1,1);
return 0;
}