LCIS(最长公共上升子序列)

LCIS(最长公共上升子序列)

方案输出+dp储存最优值优化

分析:

这道题明显是将LCS和LIS结合,那么可以想到(我没想到)定义dp[ i ] [ j ]是a中1~i 和 b中1~j 以 b[ j ] 结尾的最长LCIS长度。

转移:当a[ i ]==b[ j ]时,要在小于j中找到一个最大的dp[i-1][k]并满足b[k]<a[i] || b[k]<b[j] (因为此时a[i]==b[j],要满足上升)

优化:枚举这个k会使时间复杂度到n^3级别,所以用储存最优值的方法优化

这是没有优化的原代码

for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++){
         if(a[i]!=b[j]) dp[i][j]=dp[i-1][j];
         else{
             for(int k=1;k<j;k++)
             if(b[k]<a[i])//a[i]==b[j]
            dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
        }

优化后完整代码

//方案输出+储存最优值优化
#include<bits/stdc++.h>
using namespace std;
#define N 505
int n,m,a[N],b[N],dp[N][N],path[N][N];
void dfs(int now,int p)
{
    if(now==0) return ;
    dfs(now-1,path[now][p]);//now是现在输出到第几个了
    if(p!=path[now][p])
    printf("%d ",b[p]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    //没有优化的dp转移
    /*for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++){
         if(a[i]!=b[j]) dp[i][j]=dp[i-1][j];
         else{
             for(int k=1;k<j;k++)
             if(b[k]<a[i])//a[i]==b[j]
            dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
        }
    }*/
    //优化:储存最优值:每次用一个临时变量储存一下最优值 更新的时候直接用 而不是for一遍寻找
    //当更新完一个dp 又将最优值更新  适用范围:决策集合只增不减
    for(int i=1;i<=n;i++){
        int k=0;//k==0!! k=j-1 k的初始值一定是0!! 因为从上面未优化中可知 k的范围是:1~j-1 而 j第一次是 1
         for(int j=1;j<=m;j++){
             if(a[i]!=b[j])
              dp[i][j]=dp[i-1][j] ,path[i][j]=j;//路径输出:每次记录一下 填的这个数在b数组中的下标 然后递归输出
             else
              dp[i][j]=dp[i-1][k]+1 ,path[i][j]=k;
            //满足单调递增的条件 且j比 k优
            if( b[j]<a[i] && dp[i-1][j]>dp[i-1][k] ) k=j;//当dp被更新后 将临时变量更新一下
        }
    }
    int ans=0,pos;
    for(int i=1;i<=m;i++)
    if(dp[n][i]>ans)
     ans=dp[n][i],pos=i;
    printf("%d\n",ans);
    if(ans)
    dfs(n,pos);
}

原文地址:https://www.cnblogs.com/mowanying/p/11391213.html

时间: 2024-10-29 04:25:58

LCIS(最长公共上升子序列)的相关文章

HDU 4512 吉哥系列故事——完美队形I(LCIS最长公共上升子序列)

http://acm.hdu.edu.cn/showproblem.php?pid=4512 题意: 吉哥这几天对队形比较感兴趣. 有一天,有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则称之为完美队形: 1.挑出的人保持他们在原队形的相对顺序不变: 2.左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然,如果m是奇数,

HDU ACM 4512 吉哥系列故事——完美队形I -&gt;LCIS最长公共递增子序列

分析:最长公共递增子序列,把数据反向存储一遍,求正反两组数据的LCIS.另外注意边界的条件判断.还有如果取出的新队列有奇数个人或偶数个人要单独判断. #include<iostream> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) int dp[202]; int a[202]; int b[202]; int LCIS(int n) { int i,j,maxlen,ans; memset(dp,0,sizeof(dp

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

Description 给定两个数列,求最长公共上升子序列,并输出其中一种方案. Input&Output Input 第一行一个整数n(0<n<=500),数列a的长度. 第二行n个空格隔开的整数,数列a的元素. 第三行一个整数m,数据范围同n,数列b的长度. 第四行m个空格隔开的整数,意义同第二行. Output 第一行一个整数k,LCIS的长度. 第二行k个空格隔开的整数,其中一种方案. Solution 对于这类问题我们通常有两种转移方式,一种是以i结尾的数列,另一种是前i个数

BSOJ1004 -- 【TYVJ1071】LCIS最长公共上升子序列

Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们要研究最长公共上升子序列了. 小沐沐说,对于两个串A,B,如果它们都包含一段位置不一定连续的数字,且数字是严格递增的,那么称这一段数字是两个串的公共上升子串,而所有的公共上升子串中最长的就是最长公共上升子串了. 奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子串.不过,只要告诉奶牛它的长度就可以了. Input 第一行N,表示A,B的长度. 第

LCIS(最长公共上升子序列)Vijos1264神秘的咒语

描述 身为拜月教的高级间谍,你的任务总是逼迫你出生入死.比如这一次,拜月教主就派你跟踪赵灵儿一行,潜入试炼窟底. 据说试炼窟底藏着五行法术的最高法术:风神,雷神,雪妖,火神,山神的咒语.为了习得这些法术,要付出艰辛的努力,但是回报同样十分丰厚. 拜月希望你告诉他咒语的长度为多少.(你:“请问您想知道咒语的具体内容吗?”拜月:“想,但是vijos不支持special judge.”-_-原来大人物也有大人物的悲哀...)于是你偷偷躲在一边,想乘机看看咒语究竟是什么.突然,天空(??试炼窟底看的到天

LCIS最长公共上升子序列

定义状态 F[i][j]表示以a串的前i个整数与b串的前j个整数且以b[j]为结尾构成的LCIS的长度. 状态转移方程: ①F[i][j] = F[i-1][j] (a[i] != b[j]) ②F[i][j] = max(F[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k]) 对于①,因为F[i][j]是以b[j]为结尾的LCIS,如果F[i][j]>0那么就说明a[1]..a[i]中必然有一个整数a[k]等于b[j],因为a[k]

CodeForces 10D. LCIS 最长公共上升子序列模板题 + 打印路径

推荐一篇炒鸡赞的blog. 下面代码中有打印路径. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <map> #include <

最长公共上升子序列(LCIS)ZOJ 2432

立方算法: #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define M 505 using namespace std; typedef long long LL; LL a[M],b[M]; int dp[M][M]; int main() { //freopen("in.txt","r",stdin); in

Codeforces 10D LCIS 求最长公共上升子序列及输出这个子序列 dp

题目链接:点击打开链接 题意: 给定n长的一个序列 再给定k长的一个序列 求LCIS并输出这个子序列 如有多解输出任意解.. = - = 敲的时候听着小曲儿pre的含义还没有想清楚,万万没想到就过了... #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<mat

最长公共上升子序列(LCIS)问题的O(n^2)解法

J - 病毒 Time Limit:3000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submit Status Practice CSU 1120 Appoint description:  System Crawler  (2015-01-04) Description 你有一个日志文件,里面记录着各种系统事件的详细信息.自然的,事件的时间戳按照严格递增顺序排列(不会有两个事件在完全相同的时刻发生). 遗憾的是,