zoukankan      html  css  js  c++  java
  • Week10(线性DP)拿数问题、LIS&LCS

    Week10(线性DP)拿数问题、LIS&LCS

     

     

     思路分析:

       LIS(longest increasing subsequence)最长上升子序列,意思是一个序列中递增的序列最大个数。首先要理解子串和子序列的概念。

         (1)字符子串指的是字符串中连续的n个字符,如abcdefg中,ab,cde,fg等都属于它的字串。

         (2)字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序。如abcdefg中,acdg,bdf属于它的子序列,而bac,dbfg则不是,因为它们与字符串的字符顺序不一致。

      求LIS是DP一个基本的运用,原理就是使用一个数组d[i],表示以第i个数为结尾的最长子序列个数,求出每一个d[i]我们就可以求出答案了。而求d[i]

    的状态转移方程是max(d[i],d[j]+1),j<i .

      LCS(longest common subsequence)最长公共子序列,是指一个两个序列的公共子序列S,是满足要求的子序列中最长的,我们叫S为最长公共子序列。求LCS也是动态规划(DP)一个基本的应用。首先我们定义d[i][j],表示第一个序列前i个元素和第二个序列前j个元素的最长公共子序列的长度。d[n][m]就是我们所求的最终答案,而状态转移方程则为

       上述两个问题知道思路了代码就很好写了。

    以下为代码:

    #include <iostream>
    #include <cstdlib>
    #include <algorithm>
    #include <string.h>
    
    using namespace std;
    
    
    int a[5010];
    int b[5010];
    int fa[5010];
    int fb[5010][5010];
    
    int n,m,ans=0;
    int ans2=0;
    
    
    int main(){
        
        cin>>n>>m;
        for(int i=0; i<n; i++) {
            cin>>a[i];
            fa[i] = 1;
        }
        for(int i=0; i<n; i++)
            for(int j=0; j<i; j++)
                if(a[j]<a[i])
                    fa[i]=max(fa[i],fa[j]+1);
        for(int i=0; i<n; i++) 
            ans = max(ans, fa[i]);
        
        
        for(int i=0 ;i<m; i++){
            cin>>b[i];
        }
        
       memset(fb,0,sizeof(fb));
       
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                if(a[i-1]==b[j-1]) {
                    fb[i][j]=fb[i-1][j-1]+1;    
                }else {
                    fb[i][j]=max(fb[i-1][j],fb[i][j-1]);
                }
            }
        
        ans2=fb[n][m];
        
        cout<<ans<<" "<<ans2<<endl;
        return 0;
    }

     思路分析:

       对于课上讲的一般拿数问题,我们已经知道了它的动态表示和动态转移方程,但是这道题要求的不是相邻的不能拿,而是x+1和x-1不能拿。我们可以转化问题,将原来的序列排序,并记录每个数据出现的次数,并将这个数列填充成连续的,但是不记录填充的次数,这样,不能拿的数就必然相邻了,就可以成功将此问题转化成我们一般的拿数问题了。

    以下为代码:

    #include<iostream>
    #include<algorithm>
    
    #define LL long long 
    
    using namespace std;
    
    LL n;
    LL ans;
    LL a[100005];
    LL dp[100005];
    LL cont[100005]={0};
    
    int main(){
        cin>>n;
        
        for(LL i=0;i<n;i++){
            cin>>a[i];
            cont[a[i]]++;
        }
        
        sort(a,a+n);
        
        for(LL i=a[0];i<=a[n-1];i++){
            dp[i]=max(dp[i-1],dp[i-2]+i*cont[i]);
            ans=max(ans,dp[i]);
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    【ARM-Linux开发】C语言getcwd()函数:取得当前的工作目录
    【ARM-Linux开发】C语言getcwd()函数:取得当前的工作目录
    【ARM-Linux开发】Gstreamer+QT+摄像头 编程总结
    【ARM-Linux开发】Gstreamer+QT+摄像头 编程总结
    【ARM-Linux开发】 pkg-config的用法
    【ARM-Linux开发】 pkg-config的用法
    【ARM-Linux开发】gstreamer教程及在DM3730上的应用
    【ARM-Linux开发】gstreamer教程及在DM3730上的应用
    【ARM-Linux开发】打包解包命令
    【ARM-Linux开发】打包解包命令
  • 原文地址:https://www.cnblogs.com/Xu-SDU/p/13082716.html
Copyright © 2011-2022 走看看