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]爲以當前元素結尾的最長上升序列,那麼dp[i]=max(dp[j]j<i&&a[j]<a[i])+1dp[i]=max(dp[j] | j<i \&\& a[j]<a[i])+1,最終答案就是max(dp[i],i=1...n)max(dp[i],i=1...n)

而求解LCS則是遍歷兩個序列,設dp[i][j]dp[i][j]是到第一個序列的第ii個元素,第二個序列的第jj個元素爲止,最長的公共子序列。如果a[i]==a[j]a[i]==a[j],那麼我們就有dp[i][j]=dp[i1][j1]dp[i][j]=dp[i-1][j-1],否則有dp[i][j]=max(dp[i1][j],dp[i][j1])dp[i][j]=max(dp[i-1][j],dp[i][j-1])。因此最終結果是dp[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章