最长公共上升子序列
Posted zcxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共上升子序列相关的知识,希望对你有一定的参考价值。
输入格式
第一行包含一个整数N,表示数列A,B的长度。
第二行包含N个整数,表示数列A。
第三行包含N个整数,表示数列B。
输出格式
输出一个整数,表示最长公共上升子序列的长度。
数据范围
1≤N≤3000,序列中的数字均不超过231?1
思路:
状态表示:f[i][j]表示A数组中的前i个元素以及B数组的前j个元素,且以B[j]结尾的最长公共上升子序列
状态计算:分情况讨论,当A[i]不包含在LICS中时,那么f[i][j] == f[i-1][j]
当A[i]包含在LICS中时,由于B[j]是结尾元素,那么一定有A[i]==B[j],然后遍历1~j的所有元素k,当B[j] > B[k]时,f[i][j] == max(f[i][j], f[i-1][k] + 1)
Code: O(n3)
#include <bits/stdc++.h>
using namespace std;
const int N = 3010;
int n;
int a[N],b[N];
int f[N][N];
int main()
{
cin >> n;
for(int i = 1;i <= n;i++) cin >> a[i];
for(int i = 1;i <= n;i++) cin >> 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 ans = 0;
for(int i = 1;i <= n;i++) ans = max(ans, f[n][i]);
cout << ans << endl;
return 0;
}
这个时间复杂度在3000的数据范围内很容易TLE,我们可以想办法优化一下,优化方法就是把比较的地方的b[j]换成a[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] < a[i])
f[i][j] = max(f[i][j], f[i-1][k] + 1);
}
}
}
当换成a[i]后我们可以发现,最内层的循环与j没有什么关系,而这层循环求的就是f[i][k]的最大值 (1 <= k < j,且b[k] < a[i] (b[j])),那么我们可以用一个变量表示最大值
for(int i = 1;i <= n;i++)
{
int maxv = 0;
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 + 1);
if(b[j] < a[i]) maxv = max(maxv,f[i][j]);
}
}
最后又发现在整个DP过程中,第一维是没有用的,可以优化掉,那么就得到了最终代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3010;
int a[N],b[N];
int f[N];
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++) cin >> a[i];
for(int i = 1;i <= n;i++) cin >> b[i];
for(int i = 1;i <= n;i++)
{
int maxv = 0;
for(int j = 1;j <= n;j++)
{
if(a[i] == b[j]) f[j] = max(f[j], maxv + 1);
if(b[j] < a[i]) maxv = max(maxv,f[j]);
}
}
int ans = 0;
for(int i = 1;i <= n;i++) ans = max(ans, f[i]);
cout << ans << endl;
return 0;
}
以上是关于最长公共上升子序列的主要内容,如果未能解决你的问题,请参考以下文章