码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2020-06-13 11:03:25      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:部分   不可   name   lazy   意思   表示   最长公共子序列   ges   先后   

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;
}

 

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

标签:部分   不可   name   lazy   意思   表示   最长公共子序列   ges   先后   

原文地址:https://www.cnblogs.com/Xu-SDU/p/13082716.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!