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

[CodeForces10D]LCIS(最长公共上升子序列) - DP

时间:2018-04-02 16:03:20      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:代码   namespace   stream   ios   out   algorithm   子序列   efi   class   

Description

给定两个数列,求最长公共上升子序列,并输出其中一种方案。

Input&Output

Input

第一行一个整数n(0<n<=500),数列a的长度。
第二行n个空格隔开的整数,数列a的元素。
第三行一个整数m,数据范围同n,数列b的长度。
第四行m个空格隔开的整数,意义同第二行。

Output

第一行一个整数k,LCIS的长度。
第二行k个空格隔开的整数,其中一种方案。

Solution

对于这类问题我们通常有两种转移方式,一种是以i结尾的数列,另一种是前i个数中选择一些组成的数列。

此题中我们选用a数组前i个元素,b数组以j结尾来转移,空间为O(n^2),时间为O(n^3).其实求上升的时间可以进一步优化到O(n^2logn),但本题数据不需要。

再来说方案:维护一个LICS[i][],代表以j结尾的LICS方案,每更新一次答案,则将方案也迁移过来。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 505
using namespace std;
int n,m,a[maxn],b[maxn],f[maxn][maxn],lics[maxn][maxn];
int ans,pos;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;++i)cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;++i)cin>>b[i];
    f[0][0]=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            if(a[i]!=b[j])f[i][j]=f[i-1][j];
            else {
                f[i][j]=1;
                for(int k=1;k<j;++k){
                    if(b[k]<b[j])
                    {
                        if(f[i-1][k]+1>f[i][j]){
                            f[i][j]=f[i-1][k]+1;
                            for(int p=1;p<=f[i-1][k];++p)lics[j][p]=lics[k][p];
                        }
                    }
                }
                lics[j][f[i][j]]=b[j];
            }
        }
    for(int i=1;i<=m;++i){
        if(f[n][i]>ans)ans=f[n][i],pos=i;
    }
    printf("%d\n",ans);
    for(int i=1;i<=f[n][pos];++i)printf("%d ",lics[pos][i]);
    return 0;
}

[CodeForces10D]LCIS(最长公共上升子序列) - DP

标签:代码   namespace   stream   ios   out   algorithm   子序列   efi   class   

原文地址:https://www.cnblogs.com/nishikino-curtis/p/8693731.html

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