zoukankan      html  css  js  c++  java
  • dp求解各种子串子序列

    注:dp可能并不是求解该这些问题的最优算法,这里只是做一个dp 算法的简介。

    概念

    定义:假设现有一个 string = abcdefghijklmn

    最长连续子串:要求在原序列中连续,比如 str = abcdfghijklm都是valid substring

    最长连续子序列:相对顺序在原序列中不变即可;比如 str = afghdfkn等等都是valid subsequence

    说完了上面的定义;下面来说一说怎么用dp求解最长连续子串和最长连续子序列;既然用到了dp 的方法求解,就要找出相关的状态转移方程。

    最长上升子序列

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn=3e4+10;
    int a[maxn],b[maxn],n;
    int dp[maxn],ans;     //dp[i]表示前i个的最长上升子序列
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)   scanf("%d",&a[i]);
        for(int i=1;i<=n;++i)   scanf("%d",&b[i]);
        for(int i=1;i<=n;++i){
            dp[i]=1;
            for(int j=1;j<i;++j){
                if(a[j]<a[i]&&b[j]<b[i])    dp[i]=max(dp[i],dp[j]+1);
                ans=max(ans,dp[i]);
            }
        }
        printf("%d
    ",ans);
        system("pause");
    }
    

    最长连续子串

    递推方程:

    int f[maxn][maxn];
    int solve(char *x, char *y) 
    {
       int ans=0;
       int lenx=strlen(x);
       int leny=strlen(y);
       for (int i=0;i<lenx;i++) 
       {
           for (int j=0;j<leny;j++){
               if (x[i]!=y[j]) 		f[i][j]=0;
               else if(x[i]==y[j]) 	f[i][j]=f[i-1][j-1]+1;
               ans=max(ans,f[i][j]);
           }
        }
        return ans;
    }
    

    最长公共子序列

    状态转移方程:

    模板(花里胡哨的dp请忽略,网上版本,也可成二维数组):

    int dp[maxn][maxn];			//a[1]~a[i]与b[1]~b[j]的最长公共子序列
    int solve(int n,int m)
    {
        for (int i=0;i<=n;i++) 	dp[i][0] = 0;
        for (int i=0;i<=m;i++) 	dp[0][i] = 0;
        for (int i=1;i<=n;i++){		//n,m分别为两个数组的长度
            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-1][j],dp[i][j-1]);
            }
        }
        return dp[n][m];
    }
    

    最长公共上升子序列

    dp[i][j]的含义同最长公共子序列;

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    
    using namespace std;
    const int maxn=3e3+10;
    int a[maxn],b[maxn];
    int dp[maxn][maxn];		//表示a[1]~a[i]与b[1]~b[j]且以b[j]为结尾的最长上升公共子序列
    
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)   scanf("%d",&a[i]);
        for(int i=1;i<=n;++i)   scanf("%d",&b[i]);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                if(a[i]==b[j]){
                    dp[i][j]=1;
                    for(int k=1;k<j;++k){
                        if(b[k]<a[i])   dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
                    }
                }
                else dp[i][j]=dp[i-1][j];
            }
        }
        int ans=0;
        for(int i=1;i<=n;++i)   ans=max(ans,dp[n][i]);
        printf("%d
    ",ans);
        system("pause");
    }
    

    上面是未优化前的代码;起代码复杂度未O(n^3);其中的k循环可以被优化;优化后时间复杂度为O(n^2),看代码:

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    
    using namespace std;
    const int maxn=3e3+10;
    int a[maxn],b[maxn];
    int dp[maxn][maxn]; //表示a[1]~a[i]与b[1]~b[j]且以b[j]为结尾的最长上升公共子序列
    
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)   scanf("%d",&a[i]);
        for(int i=1;i<=n;++i)   scanf("%d",&b[i]);
        for(int i=1;i<=n;++i){
            int maxv=1;
            for(int j=1;j<=n;++j){
                dp[i][j]=dp[i-1][j];
                if(a[i]==b[j])  dp[i][j]=max(dp[i][j],maxv);
                if(b[j]<a[i])   maxv=max(maxv,dp[i][j]+1);
            }
        }
        int ans=0;
        for(int i=1;i<=n;++i)   ans=max(ans,dp[n][i]);
        printf("%d
    ",ans);
        system("pause");
    }
    
  • 相关阅读:
    hdu 1060 Leftmost Digit
    HDU 1081 To The Max 动态规划
    不安装Oracle客户端,透过PL/SQL Developer连接Server DB
    ASP.net:Ftp操作FtpWebRequest
    VS2008:log4net.dll 使用
    社会生活——《哥哥又逃票了》
    VS2008:AjaxPro.2 的应用
    Linq to SQL 根据自己需要更改数据源
    ExtJS Combobox 如何改变下拉列列宽问题
    ExtJs 的Enter特殊键事件处理
  • 原文地址:https://www.cnblogs.com/StungYep/p/12254070.html
Copyright © 2011-2022 走看看