Week 10 作业 B - B - LIS & LCS Gym - 277140A
题目描述:
求序列A的最长上升子序列长度和序列AB的最长公共子序列长度
思路:
最长上升序列:定义状态:F[i]表示考虑前i个数得到的最大值,但是用F[i-1]更新F[i]时不知道a[i]选不选;进一步:定义F[i][j]表示考虑前i个数,并且序列以a[j]结尾时得到的最大值,则很显然F[j][j]==F[i][j](i>=j时),并且i不能小于j(因为如果小于就取不到a[j]了),所以第一维是多余的;再进一步:定义F[i]表示以a[i]为结尾的最大值,则F[i]=1+max{F[j],j<i,a[j]<a[i]}
最长公共子序列:定义状态:F[i][j]表示考虑A的前i个数,B的前j个数的最大值;搜索过程:如果A[i]==B[i]则F[i][j]=F[i-1][j-1]+1;如果A[i]!=B[j]则F[i][j]=max(F[i-1][j],F[i][j-1]);边界条件:i<=0或j<=0时,返回0
代码:
#include <cstdio> #include <iostream> using namespace std; const int MAXN=5e3+5; int A[MAXN],B[MAXN]; int f[MAXN]; //f[i]表示以A[i]为结尾的上升子序列长度 int dp[MAXN][MAXN]; //dp[i][j]表示到A[i]和B[j]时的LCS长度 int main() { int N,M,LIS=0,LCS=0; cin>>N>>M; for(int i=1;i<=N;i++) scanf("%d",A+i); f[1]=1,LIS=1; for(int i=2;i<=N;i++) { for(int j=1;j<i;j++) { if(A[j]<A[i]) f[i]=max(f[i],f[j]+1); } f[i]=max(f[i],1); //如果没有前面的元素都很大,则就只包括自己,或者直接初始化F[i]=1 LIS=max(LIS,f[i]); } cout<<LIS<<' '; for(int i=1;i<=M;i++) scanf("%d",B+i); 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; }