zoukankan      html  css  js  c++  java
  • poj 3903 & poj 2533 最长上升子序列(LIS)

    最长上升子序列。

    做这道题之前先做了2533,再看这道题,感觉两道题就一模一样,于是用2533的代码直接交, TLE了;

    回头一看,数据范围。2533 N:0~1000;3903 N :1~100000。

    原因终归于算法时间复杂度。

    也借这道题学习了nlgn的最长上升子序列。(学习链接:http://blog.csdn.net/dangwenliang/article/details/5728363)

    下面简单介绍n^2 和 nlgn 的两种算法。

    n^2:

    主要思想:DP;

    假设A1,A2...Ak已经为上升子序列,下一个遇到的数是An,那么下面会遇到两种情况;

    (1) An <= Ak;这种情况,则所得上升子序列仍为A1—Ak

    (2) An > Ak;这种情况,将An添加到Ak后面,则使得新的上升子序列(A1,A2,...,Ak,An)长度为 k+1( > k);

    由此可得状态转移方程为: dp[i] = max( dp[ i ], dp[ j ]  + 1). 其中 i < j < n;

     1 #include<stdio.h>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 const int N = 1024;
     7 int seq[N];
     8 int dp[N];
     9 
    10 int main(){
    11 
    12   int n;
    13 
    14   while(~scanf("%d", &n)){
    15 
    16     for(int i = 1; i <= n; ++i){
    17         scanf("%d", &seq[i]);
    18         dp[i] = 1; // 初始长度为1
    19     }
    20     for(int i = 2; i <= n; ++i)
    21         for(int j = 1; j < i; ++j)
    22           if(seq[j] < seq[i])
    23             dp[i] = max(dp[i],dp[j] + 1);
    24     int mlen = -1;
    25     for(int i = 1; i <= n; ++i)
    26       mlen = max( mlen,  dp[i] );
    27     printf("%d
    ", mlen);
    28   }
    29 
    30   return 0;
    31 
    32 }
    View Code

    容易看出该时间复杂度为 n^2;

    nlgn:

    主要思想:二分;

    假设A1,A2...Ak已经为上升子序列,若此时存在:

    (1) Am < Ap < An;(1< m < n < k, p > m)

    (2)length of A1...Am, An...AK == length of A1...Ap, An...Ak;

    显然, A1...Ap, An...Ak 会比 A1...Am, An...AK更优。为什么呢?

    如果此时存在 q , p < q < n, 使得Ap < Aq < An,则有长度为 k+1 ( > k)的上升子序列。

    由此,我们可以得出一种思路:

    用一个数组C[ ],来存放长度为 s 的最长上升子序列中的最小值。(1 <= s < len, len为A中最长上升子序列的长度)

    可知C有如下特点:

    (1) C为不下降序列。(此特点为可以使用二分的条件)

    (2) C的长度即为最长上升子序列的长度。

    那么, 对于Clen, 如果下一个要考虑是否添加进入上升序列的元素为At,有At > Clen,则将At添入C的末尾,可得新的上升子序列,此序列长度为 len + 1;

                             如果有At < Clen,则找到 j ,使得Aj为所有小于At中的最大值,若不存在与 At 相等的值,则把At插入 j+1 这个位置,会新得到一个长度为len + 1的上升子序列。(由于C是有序的,所以查找j的时候可以采用二分法);

    但最后得到的C,不是A中的最长上升子序列。( 该算法的正确性我也无法证明,而且没有搜到该算法的证明 )

     1 #include<stdio.h>
     2 
     3 const int N = 100008;
     4 
     5 int num[N], c[N];
     6 
     7 int bin(int *a, int len, int n){
     8 
     9    int left = 0, right = len, mid = (left + right) >> 1;
    10    while(left <= right){
    11 
    12        if(n > a[mid]) left = mid + 1;
    13        else if( n < a[mid] ) right = mid - 1;
    14        else return mid;
    15        mid = ( left + right ) >> 1;
    16 
    17    }
    18    return left;
    19 
    20 }
    21 
    22 int main(){
    23 
    24 
    25    int n;
    26    while(~scanf("%d", &n)){
    27 
    28     for(int i = 0; i < n + 1; i++) //为什么要到n+1呢?
    29         c[i] = 1000000;
    30 
    31     for(int i = 0; i < n; i++)
    32         scanf("%d", &num[i]);
    33     c[0] = -1;//c[0] = -1??为什么
    34     c[1] = num[0];
    35     int len = 1;
    36     for(int i = 1; i < n; i++){
    37         int k = bin(c, n+1, num[i]);
    38         c[k] = num[i];
    39         if( k > len)
    40             len = k;
    41     }
    42     printf("%d
    ", len);
    43    }
    44 
    45    return 0;
    46 
    47 }
    View Code

    此时时间复杂度为nlgn。

                                                                                                                                                                                    END

    如有任何问题,欢迎指教。

  • 相关阅读:
    spring cloud 和 阿里微服务spring cloud Alibaba
    为WPF中的ContentControl设置背景色
    java RSA 解密
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Hystrix 配置参数全解析
    spring cloud 2020 gateway 报错503
    Spring Boot 配置 Quartz 定时任务
    Mybatis 整合 ehcache缓存
    Springboot 整合阿里数据库连接池 druid
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
  • 原文地址:https://www.cnblogs.com/pekary/p/3873164.html
Copyright © 2011-2022 走看看