Input
第一行一个整数 N,表示数列 A , B 的长度。
第二行 N 个整数,表示数列 A
第三行 N 个整数,表示数列 B
序列中的数字均不超过 231 - 1
Output
一个整数,表示最长公共上升子序列的长度
Sample Input
4
2 2 1 3
2 1 2 3
Sample Output
2
朴素版代码:
思路:结合LIS和LCS容易想到,f[i,j]表示a1~ai与b1~bi可以构成的以bj为结尾的LCIS的长度。
当ai!=bj时,直接f[i][j]=f[i-1][j];
当ai==bj时,f[i][j]=max(f[i][j] , f[i-1][k]+1); k<j且b(k)<b(j).通过枚举倒数第二位的值找到最大值。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int ,int>PII;
typedef long long ll;
int ans,sum;
const int N=3010;
int a[N],b[N];
int f[N][N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
f[i][j]=f[i-1][j];
if(a[i]==b[j])
{
f[i][j]=max(f[i][j],1);
for(int k=1;k<j;k++)
if(b[k]<b[j])
f[i][j]=max(f[i][j],f[i-1][k]+1);
}
}
int sum=0;
for(int i=1;i<=n;i++)
sum=max(sum,f[n][i]);
printf("%d",sum);
return 0;
}
优化版代码:
思路:在朴素版代码中,第一层循环的i是定值,这使得条件b(k)<a(j)是固定的,当j变为j+1时,k的范围从0~j变为0~j+1,又因为f[i][j]的状态都是从f[i-1][j]转移过来,故可以用一个maxv记录f[i-1][k]的最大值+1的值,(k<j),当a[i]==b[j]时,直接有f[i][j]=maxv,当a[i]!=b[j]时,f[i][j]=f[i-1][j],同时需要更新maxv的值。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int ,int>PII;
typedef long long ll;
int ans,sum;
const int N=3010;
int a[N],b[N];
int f[N][N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
{
int maxv=1;
for(int j=1;j<=n;j++)
{
f[i][j]=f[i-1][j];
if(a[i]==b[j]) f[i][j]=max(f[i][j],maxv);
if(b[j]<a[i]) maxv=max(maxv,f[i-1][j]+1);
}
}
int sum=0;
for(int i=1;i<=n;i++)
sum=max(sum,f[n][i]);
printf("%d",sum);
return 0;
}