zoukankan      html  css  js  c++  java
  • POJ 2127 DP(n^2)

    题意:

    最长公共上升子序列

    思路:

    以前都是写的n^3的,今天听说有n^2算法,就看了一下。其实就是n^3的优化

    以前n^3的方程是:

    dp[i][j]表示以a串的前i个数字且以b[j]结尾的的最大的LCIS的长度

    转移是:

    dp[i][j]=max(dp[i][j],dp[i-1][k]+1)    a[i]==b[j]&&b[k]<b[j]   1<=k<j

    dp[i][j]=max(dp[i][j],dp[i-1][j])     a[i]!=b[j]

    现在开始优化:

    第一个方程是n^3的,i,j两层循环是肯定干不掉的,那我们就想办法干掉k的这层循环

    可以观察发现循环i层的状态是由i-1层转移过来的,这样就暗示我们要优化循环顺序,i的循环在外部,j的循环在内部

    这样我们才可以降低复杂度:

    考虑以下不等式:

    a[i]==b[j]>b[k]    ------>    a[i]>b[k]

    (仔细想想上面的不等式能给你启发)

    那么!这个东西可以再上一层循环中求出来!发现没有?

    在进入内层循环时,就可以维护一个最大值ma;

    当b[j]<a[i]时,ma=max(ma, dp[i-1][ j])

    当出现b[j]==a[i]时,就可以直接取dp[i][j]=ma+1

    (说白了,就是把k的循环用j充当了。)

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <string>
     5 #include <iostream>
     6 
     7 #define N 600
     8 
     9 using namespace std;
    10 
    11 int n,m,a[N],b[N],dp[N][N],pre[N][N],stk[N];
    12 
    13 void go()
    14 {
    15     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    16     scanf("%d",&m);
    17     for(int j=1;j<=m;j++) scanf("%d",&b[j]);
    18     memset(dp,0,sizeof dp);
    19     dp[0][0]=0;
    20     for(int i=1,ma,last;i<=n;i++)
    21     {
    22         ma=0;last=0;
    23         for(int j=1;j<=m;j++)
    24         {
    25             if(a[i]==b[j])
    26             {
    27                 dp[i][j]=ma+1;
    28                 pre[i][j]=last;
    29             }
    30             else dp[i][j]=max(dp[i][j],dp[i-1][j]);
    31             if(b[j]<a[i]&&ma<dp[i-1][j])
    32             {
    33                 ma=dp[i-1][j];
    34                 last=j;
    35             }
    36         }
    37     }
    38     int ans=-1,x=n,y,p=0;
    39     for(int j=1;j<=n;j++)
    40         for(int i=1;i<=m;i++)
    41             if(ans<dp[j][i])
    42             {
    43                 ans=dp[j][i];
    44                 y=i;
    45             }
    46     printf("%d\n",ans);
    47     
    48     while(ans--)
    49     {
    50         stk[++p]=b[y];
    51         while(a[x]!=b[y]) x--;
    52         y=pre[x][y];
    53         x--;
    54     }
    55     for(int i=p;i>=1;i--) printf("%d ",stk[i]);
    56 }
    57 
    58 int main()
    59 {
    60     while(scanf("%d",&n)!=EOF) go();
    61     return 0;
    62 }
    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    二人pk答题小程序
    题解【CF911F】Tree Destruction
    题解【洛谷P5765】[CQOI2005]珠宝
    WC2021 游记
    生产环境财务BUG的排查与总结
    生产环境一个订单状态错误的排查与反思
    《HeadFirstServletAndJsp》笔记一
    Java泛型简介二
    Java泛型简介一
    在Windows环境下与Linux环境下快速计算文件Hash
  • 原文地址:https://www.cnblogs.com/proverbs/p/2712029.html
Copyright © 2011-2022 走看看