题目描述
东东有两个序列A和B。
他想要知道序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。
Input
第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)
第二行n个数,表示序列A
第三行m个数,表示序列B
Output
输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度
Simple Input
5 5
1 3 2 5 4
2 4 3 1 5
Simple Output
3 2
题目分析
术语解释:
LIS:最长上升子序列 (Longest Increasing Subsequence)
LCS:最长公共子序列 (Longest Common Subsequence)
本题使用动态规划,先求得子问题的解,然后决策。
LIS:
定义f[i]表示以Ai为结尾的最长上升序列的方程,初始化f[i]=1,转移方程如下:
f
i
=
m
a
x
{
f
j
∣
j
<
i
&
A
j
<
A
i
}
+
1
f_i=max\{f_j|j<i \& A_j<A_i\}+1
fi=max{fj∣j<i&Aj<Ai}+1
最后求出max{f[i]}即可,时间复杂度为O(n2)
LCS:
假设f[i][j] 为A1,A2…A和B1,B2…B的LCS长度,初始化f[0][1] f[1][0] f[0][0]为0,转移方程如下:
A
i
=
=
B
j
−
−
>
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
+
1
A_i==B_j -->f[i][j]=f[i-1][j-1]+1
Ai==Bj−−>f[i][j]=f[i−1][j−1]+1
否
则
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
j
]
,
f
[
i
]
[
j
−
1
]
)
否则f[i][j]=max(f[i-1][j],f[i][j-1])
否则f[i][j]=max(f[i−1][j],f[i][j−1])
最后输出答案f[n][m]即可,时间复杂度O(nm)
注意
大数组一定不要在main内定义,轻轻松松爆栈,内存栈没我们想的那么大
代码
#define _ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include <bits/stdc++.h>
using namespace std;
int LIS[5009];
int LCS[5009][5009];
int main()
{
// freopen("week10/in.txt","r",stdin);
int a,b;
cin>>a>>b;
int A[5009],B[5009];
for(int i=1;i<=a;i++)cin>>A[i];
for(int i=1;i<=b;i++)cin>>B[i];
//LIS for A
LIS[1]=1;
for(int i=2;i<=a;i++)
{
int temp=1;
for(int j=1;j<=i-1;j++)
{
if(A[j]<A[i])
if(LIS[j]>=LIS[temp])
temp=j;
}
if(A[temp]>=A[i])LIS[i]=1;//前i-1个没有合适的
else LIS[i]=LIS[temp]+1;
}
int temp=LIS[1];
for(int i=1;i<=a;i++)
temp=LIS[i] > temp ? LIS[i] : temp;
cout<<temp<<' ';
//LCS for A&B
LCS[1][0]=LCS[0][1]=LCS[0][0]=0;
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
if(A[i]==B[j])LCS[i][j]=LCS[i-1][j-1]+1;
else LCS[i][j]=max(LCS[i-1][j],LCS[i][j-1]);
cout<<LCS[a][b];
return 0;
}