LCS问题
求两序列具有相同元素的最长子序列,我们可以用到动态规划的方法来解决问题
我们用 来表示序列 与序列 能组成的LCS的长度,的状态转移方程如下:
使用两层for循环就可以解决此问题,时间复杂度为,可以处理n<7000左右的数据
例题: 最长公共子序列(LCS) 问题 11426
题目描述
给出1-n的两个排列P1和P2,求它们的最长公共子序列。
输入描述
第一行是一个数n;(n是5~1000之间的整数)
接下来两行,每行为n个数,为自然数1-n的一个排列(1-n的排列每行的数据都是1-n之间的数,但顺序可能不同,比如1-5的排列可以是:1 2 3 4 5,也可以是2 5 4 3 1)。
输出描述
一个整数,即最长公共子序列的长度。
#include<bits/stdc++.h>
using namespace std;
int n;
int a[1001],b[1001];
int f[1001][1001];
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++)
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][n];
}
而此题有一变式,即 ,很明显 的时间复杂度已经解决不了这个问题了,有一种 的做法是通过map将 映射为高度,然后求b序列的最长单调递增队列,将LCS转换为LIS问题,当然这种方法只适用于 时。
#include<bits/stdc++.h>
using namespace std;
int n;
int a[1000001],b[1000001];
int f[1000001];
map<int,int> mp;
int len;
int main() {
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i],mp[a[i]]=i;//将a[i]映射为高度
for(int i=1; i<=n; i++)
cin>>b[i];
for(int i=1; i<=n; i++) { //找最长单调递增序列
if(mp[b[i]]>f[len])
f[++len]=mp[b[i]];
else {
int loc=lower_bound(f,f+len,mp[b[i]])-f;
if(loc)
f[loc]=mp[b[i]];
}
}
cout<<len;
}