题意:
东东有两个序列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
思路:
想要求最长上升子序列,我们若是用dp[i]来表示以第i个数为最后一位的上升子序列的长度,对于数列中第i个数A[i],dp[i]的值应该为他之前元素比他小的所有的位置的d[j]中的最大加1,即dp[i] = max{dp[j] | j<i && A[j] < A[i]} + 1;
想要求最长公共子序列,我们可以设立二维的dp数组,dp[i][j]表示在A数组中的i+1位置之前和B数组中的j+1位置之前的最长公共子序列的长度,关于他的更新,当我们在遍历的时候碰到A[i] == B[j]时,dp[i][j] = dp[i-1][j-1] + 1,若是不等的话,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
总结:
求LIS:dp[i] = max{dp[j] | j<i && A[j] < A[i]} + 1
求LCS:A[i] == B[j]时,dp[i][j] = dp[i-1][j-1] + 1,若是不等的话,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。
构造状态转移方程是求解动态规划问题中最重要的一步。
代码:
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int n, m;
long long A[5005];
long long B[5005];
int getLIS()
{
int dp1[5005];
dp1[1] = 1;
int ans = dp1[1];
for (int i = 2; i <= n; i++)
{
int t = 0;
for (int j = 1; j < i; j++)
{
if (A[j]<A[i] && dp1[j]>t)t = dp1[j];
}
dp1[i] = t + 1;
ans = max(dp1[i], ans);
}
return ans;
}
int getLCS()
{
int dp[5005][5005];
dp[0][0] = 0;
dp[1][0] = 0;
dp[0][1] = 0;
for (int i = 0; i <= m; i++)dp[0][i] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (A[i] == B[j])dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
return dp[n][m];
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)scanf("%lld", &A[i]);
for (int i = 1; i <= m; i++)scanf("%lld", &B[i]);
printf("%d %d", getLIS(),getLCS());
}