LCS(记录路径)+LIS+LCIS

https://blog.csdn.net/someone_and_anyone/article/details/81044153

当串1 和 串2 的位置i和位置j匹配成功时,

dp[i][j]=dp[i-1][j-1]+1,也就是说此状态由状态dp[i-1][j-1]转移而来,用数组记录为1,

当匹配不成功时,dp[i-1][j]和dp[i][j-1]去一个最大的,用数组分别记为2和3.

根据记录数组寻找路径:

当记录数组为1时,说明次时的i和j想等,并且此状态由i-1和j-1转移而来,所以i=i-1,j=j-1

当记录数组为2时,说明此时i和j对应的数符不等,并且此状态由j-1转移而来,所以直接j--;

当记录数组为2时,说明此时i和j对应的数符不等,并且此状态由i-1转移而来,所以直接i--;

例题:

#include<bits/stdc++.h>
using namespace std;
const int N=1000+7;
int dp[N][N];
int mark[N][N];
char s1[N],s2[N];
int main()
{
    cin>>s1+1>>s2+1;
    int n=strlen(s1+1);
    int m=strlen(s2+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(s1[i]==s2[j]){
                dp[i][j]=dp[i-1][j-1]+1;
                mark[i][j]=1;
            }
            else if(dp[i][j-1]>dp[i-1][j]){
                dp[i][j]=dp[i][j-1];
                mark[i][j]=2;    
            }
            else {
                dp[i][j]=dp[i-1][j];
                mark[i][j]=3;
            }
         }
    string ans="";
    int i=m,j=n;
    while(i>0&&j>0){
        if(mark[i][j]==1) {
            ans+=s1[i];
            i--;j--;
        }
        else if(mark[i][j]==2) {
            j--;
        }
        else i--;
    }
    reverse(ans.begin(),ans.end());
    cout<<ans<<endl;
    
    return 0;
}

 LIS:最长上升子序列。

O(n^2):

  定义dp[i]表示考虑到第i个元素,他可以拼接到从1~i-1中比它小的元素上去。

  dp[i]=max(dp[k])+1,代码比较简单,在此省略。

O(nlogn):

  定义dp[len]表示当长度为len时的最小元素。

code:

  

dp[1]=a[1];
int len=1;
for(int i=1;i<=n;i++){
    if(a[i]>dp[len]) dp[++len]=a[i];
    else *lower_bound(dp+1,dp+1+len,a[i])=a[i];
}

LCIS:最长公共上升子序列

定义状态dp[i][j]表示考虑前i个字符时,当选中第j个字符时的状态。

在这里第j个字符已经选了,所以前i个字符一定有和它匹配的,当第j个字符和第i个字符不匹配成功时,那第j个字符一定和

前i-1中的一个字符匹配喽,所以转移方程为dp[i][j]=dp[i-1][j],还是以j结尾。

当第j个字符和第i个字符匹配成功时,dp[i][j]=max(dp[i-1][k])+1,要在和前i-1个匹配的字符中选出状态最好的。

所以状态转移方程为:

dp[i][j]=dp[i-1][j],匹配成功。

dp[i][j]=max(dp[i-1][k])(k<=j)匹配不成功。

code:

void solve(int t){
    ll n,m; 
    cin >> n;
    for (ll i = 1; i <= n; i++) cin >> arr[i];;
    cin >> m;
    for (ll i = 1; i <= m; i++) cin >> brr[i];
    ll mx = 0;
    for (ll i = 1; i <= n; i++) {
        mx = 0;
        for (ll j = 1; j <= m; j++) {
            dp[i][j] = dp[i - 1][j];
            if (brr[j] < arr[i]) mx = max(mx, dp[i-1][j]);
            else if (arr[i] == brr[j]) dp[i][j] = mx + 1;
        }
    }
    ll ans = 0;
    for (ll i = 1; i <= m; i++)  ans = max(ans, dp[n][i]);
    cout << ans<<"
"<<"
"; 
}

一个例题:

HDU1423:Greatest Common Increasing Subsequence

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1E3 + 7;
ll arr[N];
ll brr[N];
ll dp[N][N];
void solve(int t){
    ll n,m; 
    cin >> n;
    for (ll i = 1; i <= n; i++) cin >> arr[i];;
    cin >> m;
    for (ll i = 1; i <= m; i++) cin >> brr[i];
    ll mx = 0;
    for (ll i = 1; i <= n; i++) {
        mx = 0;
        for (ll j = 1; j <= m; j++) {
            dp[i][j] = dp[i - 1][j];
            if (brr[j] < arr[i]) mx = max(mx, dp[i-1][j]);
            else if (arr[i] == brr[j]) dp[i][j] = mx + 1;
        }
    }
    ll ans = 0;
    for (ll i = 1; i <= m; i++)  ans = max(ans, dp[n][i]);
    cout << ans<<"
";
    if(t) cout<<"
"; 
}
int main(){
    ll t;
    cin >> t;
    while (t--) solve(t);
    return 0;
}
原文地址:https://www.cnblogs.com/Accepting/p/12457402.html