动态规划入门——子序列问题

一 最长上升子序列(LIS)

【题目描述】

给定N个数,求这N个数的最长上升子序列的长度

【样例输入】

7

2 5 3 4 1 7 6

【样例输出】

4

分析:

维护一个子序列,遍历母序列,子序列的第一个元素是母序列的第一个元素,然后依次比较母序列的每个元素A和子序列的最后一个元素B的大小关系,如果A>B,那么将A放在子序列的后面,否则,在子序列中找到第一个大于或等于A的元素,将其更换为A(这里用的是二分查找),时间复杂度为O(n*logn)

代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1000 + 5;

int a[maxn];
int dp[maxn];
int main(){
    int n;
    cin>>n;
    for(int i = 0 ; i < n ; i ++ ) cin>>a[i];
    dp[0] = a[0];
    int k = 1;
    for(int i = 1 ; i < n ; i ++ ){
        if(a[i]>dp[k-1]) dp[k++] = a[i];
        else{
            int p = lower_bound(a,a+n,a[i]) - a ;
            dp[p] = a[i] ;
        }
    }
    cout<<k<<endl;
}

二 最长公共子序列(LCS)

【题目描述】

给定两个字符串 s , t ,求出这两个字符串最长的公共子序列的长度。

【样例输入】

n = 4

m = 4

s = "abcd"

t = "becd"

【样例输出】

3("bcd")

分析:

将dp[i][j]定义为 s1....si 和t1....tj 的对应LCS的长度

由此,s1....si+1和t1....tj+1对应的公共子序列可能为

  1)当 si+1 = tj+1 时 在其现在的LCS的末尾加上 si+1;

  2)s1....si 和 t1....tj+1 的公共子序列

  3)s1....si+1 和 t1....tj 的公共子序列

代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1000 + 5;

char s[maxn],t[maxn];
int n,m;
int dp[maxn+1][maxn+1];

int main(){
    cin>>n>>m;
    cin>>s>>t;
    for(int i = 0 ; i < n ; i ++ ){
        for(int j = 0 ; j < m ; j ++ ){
            if(s[i]==t[j])
                dp[i+1][j+1] = dp[i][j] + 1;
            else
                dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]);
        }
    }
    cout<<dp[n][m]<<endl;
}


猜你喜欢

转载自blog.csdn.net/insist_77/article/details/80271798
今日推荐