题意:

input:

output:

思路:
1、最长上升子序列,对于给定的一串数,定义f[i]为以A[i]结尾的长度。转移方程为fi=max{fj | j<i && Aj<Ai}+1。首先将第一个数的长度赋为1,从第一个数开始遍历,到第i个数的时候,遍历 j 为0到i-1的数,其中A[j]要比当前的A[i]小,才能接上去,找到在这其中的已有的最大的f[j],将f[i]接上去,并加1,即可得到最大的。复杂度n^2.
2、最长公共子序列,对于给定的两串数,设f[i][j]为A[]数组遍历到i,B[]数组遍历到j的时候,其两个的相同的数。
首先初始化f[i][0],f[0][j], f[0][0],都为0。易知,其不会有相同的数。
状态转移:即对当前的A[i]和B[i],如果相等,则已有的数加1,并计算其f[i-1][j-1]的个数,并加上1。若不相等,则其中的一个回退1,并取两个回退的最大值,即
f[i][j]=max(f[i-1][]j,f[i][]j-1);即为枚举其中一个数组的数,然后遍历另外一个数组的数,来求得最大的数。
综上,转移方程为: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)。
代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m;
long long A[5010], B[5010];
long long f1[5010]; //记录最长上升子序列
long long f[5010][5010];
long long ans1=0;
int main() {
ios::sync_with_stdio(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> A[i];
}
for(int i=1; i<=m; i++){
cin>>B[i];
}
memset(f1, 0, sizeof(f1));
memset(f, 0, sizeof(f));
f1[1] = 1;
for (int i = 1; i <= n; i++) {
long long m1 = 0;
for (int j = 1; j < i; j++) {
if (A[j] < A[i]) m1 =max(m1,f1[j]);
}
f1[i]=m1+1;
ans1 = max(ans1,f1[i]);
}
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<<ans1<<" "<<f[n][m]<<endl;
return 0;
}
本文深入探讨了两种关键的序列算法——最长上升子序列与最长公共子序列。详细讲解了各自的定义、状态转移方程及其实现代码,为理解序列算法提供了清晰的路径。
223

被折叠的 条评论
为什么被折叠?



