SDU程序设计思维Week10-作业
B-LIS & LCS
Description
给定两个序列A和B。
求序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1<a2<…<ak(ai<=1,000,000,000)。
输入第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)
第二行n个数,表示序列A
第三行m个数,表示序列B
输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度
Sample
Input:
6 7
1 5 2 6 8 7
2 3 5 6 9 8 4
Output:
4 3
Idea
题意:分别计算LIS和LCS
LIS:
根据转移方程,扫描每个数时,找到以小于该数的a为结尾的上升序列中长度最长的序列,加上该数就构造了以该数为结尾的最长上升序列
最后搜索所有长度的最大值即答案
LCS:
- 设 t[i][j] 为 A 1 , A 2 , …, A i 和 B 1 , B 2 , …, B j 的 LCS 长度
- 初始化:初始 t[1][0] = t[0][1] = t[0][0] = 0
- 转移方程:当 A i == B j 时,t[i][j] = t[i-1][j-1] + 1,否则 t[i][j] = max(t[i-1][j], t[i][j-1])
根据转移方程,扫描二维数组 - 最大公共子序列的长度:t[n][m]
Summary
LIS和LCS是动态规划的经典应用,关键在于构造转移方程
LIS时间复杂度为O(n^2)
LCS时间复杂度为O(nm)
Codes
#include <iostream>
#include <algorithm>
using namespace std;
int n, m;
int f[5020],a[5020],b[5020],t[5020][5020];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= m; i++)
cin >> b[i];
int ans1 = 0, ans2 = 0;
f[1] = 1;
for (int i = 2; i <= n; i++) {
int maxn = 0;
for (int j = 1; j < i; j++) {
if(a[j]<a[i])maxn = maxn > f[j] ? maxn : f[j];
}
f[i] = maxn + 1;
}
for (int i = 1; i <= n; i++)
ans1 = ans1 > f[i] ? ans1 : f[i];
//cout << ans1 << endl;
t[1][0] = t[0][1] = t[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i] == b[j])t[i][j] = t[i - 1][j - 1] + 1;
else t[i][j] = max(t[i - 1][j], t[i][j - 1]);
}
}
ans2 = t[n][m];
cout << ans1 << " " << ans2 << endl;
}