LIS & LCS(动态规划)

问题描述

东东有两个序列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的长度

解题思路

这个题是基本的动态规划问题,LIS是最长上升子序列,LCS是最长公共子序列。

求解LIS就是设dp[i]为以当前元素结尾的最长上升序列,那么 d p [ i ] = m a x ( d p [ j ] j < i & & a [ j ] < a [ i ] ) + 1 dp[i]=max(dp[j] | j<i \&\& a[j]<a[i])+1 ,最终答案就是 m a x ( d p [ i ] , i = 1... n ) max(dp[i],i=1...n)

而求解LCS则是遍历两个序列,设 d p [ i ] [ j ] dp[i][j] 是到第一个序列的第 i i 个元素,第二个序列的第 j j 个元素为止,最长的公共子序列。如果 a [ i ] = = a [ j ] a[i]==a[j] ,那么我们就有 d p [ i ] [ j ] = d p [ i 1 ] [ j 1 ] dp[i][j]=dp[i-1][j-1] ,否则有 d p [ i ] [ j ] = m a x ( d p [ i 1 ] [ j ] , d p [ i ] [ j 1 ] ) dp[i][j]=max(dp[i-1][j],dp[i][j-1]) 。因此最终结果是 d p [ n ] [ m ] dp[n][m]

完整代码

//#pragma GCC optimize(2)
//#pragma G++ optimize(2)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int maxn=5000+10;
int n,m,a[maxn],b[maxn],dp1[maxn],dp2[maxn][maxn],ans;
int getint(){
    int x=0,s=1; char ch=' ';
    while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
    while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
    return x*s;
}
int main(){
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    n=getint(); m=getint();
    for (int i=1; i<=n; i++) a[i]=getint(),dp1[i]=1;
    for (int i=1; i<=m; i++) b[i]=getint();
    for (int i=1; i<=n; i++){
        for (int j=1; j<i; j++)
            if(a[j]<a[i]) dp1[i]=max(dp1[i],dp1[j]+1);
        ans=max(ans,dp1[i]);
    }
    for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            if(a[i]==b[j]) dp2[i][j]=dp2[i-1][j-1]+1;
            else dp2[i][j]=max(dp2[i-1][j],dp2[i][j-1]);
        }
    }
    printf("%d %d\n",ans,dp2[n][m]);
    return 0;
}
原创文章 61 获赞 58 访问量 6481

猜你喜欢

转载自blog.csdn.net/weixin_43347376/article/details/105732107
今日推荐