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

 

posted on 2019-08-21 21:02  rua-rua-rua  阅读(377)  评论(0编辑  收藏  举报