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


    题目大意:

    给定两个数字数组a[] , b[],在这两个数组中找一个最长的公共上升子序列,输出最长的长度

    从别人地方copy的= = LCIS理解:

    (1)f[i][j] 表示 a的前i,和b串前 j,以b[j]结尾的LCIS的长度;

    if(a[i]!=b[j) f[i][j]=f[i-1][j];

    else       f[i][j]=max(f[i-1][k]+1) 1<=k<j&&b[k]<b[j];

     

    O(n^3)的复杂度,因为多了一维k,但f[i-1][k]的最大值显然可以在处理i-1的时候求出来

    for(i=1;i<=n;i++)

         maxn=0;

              for(j=1;j<=m;j++)

                   f[i][j]=f[i-1][j];

                   if(a[i]>b[j]&&maxn<f[i-1][j])  maxn=f[i-1][j];

                   if(a[i]==b[j])    f[i][j]=maxn+1;

     

     

    最后扫一遍f[n][1......m] ,取最大值。

     

    (2)压缩空间,时间不变:

           用f[j]表示 所有的a[i]和b的前j个,以b[j]结尾的LCIS的长度。

         注意到(1)中,  if(a[i]>b[j]&&maxn<f[i-1][j])  maxn=f[i-1][j];  我们取得其实是f[1..i-1][j]的最大值,那不就是f[j]吗?

     

       int f[N];

       int a[M],b[N];

       memset(f,0,sizeof(f));

       for(i=1;i<=M;i++)

            maxn=0;

            for(j=1;j<=N;j++)

                  if(a[i]>b[j]&&maxn<f[j]) maxn=f[j];

                  if(a[i]==b[j])   f[j]=maxn+1;

    最后扫一遍f[1......N];

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 using namespace std;
     5 const int N = 1005;
     6 #define max(a,b) a>b?a:b
     7 int dp[N] , a[N] , b[N];
     8 /*可以看作是每次在第一个数据中提取一个数字,然后在第二个数组中
     9 根据相同的数字来查找最长上升子序列,f[i][j],表示a[]前i个数据和
    10 b数组前j个数据中能找到的以a[i]结尾的最长上升子序列的长度
    11 但是因为下一行总是和前面所有行有关,不断更新找到前j个位置以某一个数结尾
    12 的最大值,如果还是采用二维的,我们必须
    13 if(a[i] == b[j])的时候,回过去建立
    14 for(t = 1 ; t<i ; t++)
    15     dp[i][j] = max(dp[i][j] , dp[t][k]+1);
    16 复杂度就变成了n的3次方
    17 这里压缩为1维数组的同时,不断更新到第j个位置所能达到的最大值
    18 */
    19 void LCIS(int m , int n)
    20 {
    21     memset(dp , 0 , sizeof(dp));
    22     for(int i = 1 ; i<=m ; i++){
    23         /*
    24         对于任意的f[i],f[j]来说,只要i>j,那么f[i]>f[j]的
    25         这里k就是用来不断更新到离i最近的一个满足上升的位置
    26         这样从离它最近的位置处进行更新这样得到的数据一定是
    27         满足最优子结构的
    28         比如2 , 3 , 5三个数,当把5加进来,直接用f[2]+1即可,
    29         因为f[1]<=f[2]这是必定的,所以没必要执行f[1]+1,这样
    30         就取消了重叠子结构的计算
    31         */
    32         int  k = 0;
    33         for(int j = 1 ; j<=n ; j++){
    34             if(a[i] == b[j]) dp[j] = max(dp[j] , dp[k] + 1);
    35             //只有大于的时候才更新k,表示离它最近的满足的最长上升子序列的位置
    36             if(a[i] > b[j] && dp[k] < dp[j]) k = j;
    37         }
    38     }
    39 }
    40 
    41 int main()
    42 {
    43     int m , n , T;
    44     scanf("%d" , &T);
    45     while(T--){
    46         scanf("%d" , &m);
    47         for(int i = 1 ; i<=m ; i++)
    48             scanf("%d" , a+i);
    49 
    50         scanf("%d" , &n);
    51         for(int i= 1 ; i<=n ; i++)
    52             scanf("%d" , b+i);
    53 
    54         LCIS(m , n);
    55         int maxn = 0;
    56         for(int i = 1 ; i <= n ; i++)
    57             maxn = max(maxn , dp[i]);
    58 
    59         printf("%d
    " , maxn);
    60         if(T>0) puts("");
    61     }
    62     return 0;
    63 }
  • 相关阅读:
    docker指令汇总
    springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理
    RabbitMQ 消息确认机制
    RabbitMQ 最常用的三大模式
    RabbitMQ 核心概念
    RabbitMQ 之简单队列
    Spring 详解(三)------- SpringMVC拦截器使用
    slf4j 搭配 log4j2 处理日志
    Spring 详解(二)------- AOP关键概念以及两种实现方式
    Spring 详解(一)------- AOP前序
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4182618.html
Copyright © 2020-2023  润新知