1269: 求最长上升子序列(LIS)

 题目描述

LIS问题(longest increasing subsequence),即:最长上升子序列问题,是动态规划中一个比较经典的问题。具体描述为:一个有n个整数的序列:A[1],A[2],…,A[n],求出该序列中最长上升子序列的长度。例如:5,3,4,8,它的上升子序列有:
5
3
4
8
3 4
3 8
4 8
3 4 8
最长的上升子序列的长度为3

 

 输入:

 

共2行
第1行:n(表示序列的长度 1 <= n < 10000)
第2行:n个用空格隔开的整数(0 <= 每个整数 <= 108)

 

 输出:

 

最长上升子序列的长度
 样例输入:
6
5 3 4 8 6 7

 样例输出:

4

 


 

 思路(n log n 做法):

首先,我们就要改变dp数组的含义

dp[i]:数列长度为2的LIS结尾最小的数

e.g. dp[2] = 3(本身) ,dp[3] = 4。(样例)

我们就可以遍历每一个a[i],找到第一个比它大(不是大于等于!!!)的dp数,并将这个dp末尾最小的数更新为a[i],如果更新完后长度大于目前LIS的最长长度,就更新长度。(核心部分,用二分lower_bound


 

 代~~码~~:

 

#include <bits/stdc++.h>
using namespace std;
#define INF INT_MAX//正无穷 
#define XINF INT_MIN//负无穷 
  
int dp[10005],a[10005]; 
int n;
  
int main(){
    scanf("%d",&n);
      
    for (int i = 1;i <= n;i++){
        scanf("%d",&a[i]);
        dp[i] = INF;
    }//输入,将dp值赋为正无穷 
      
    dp[0] = XINF;//将dp[0]赋为负无穷 
    int len = 0;//LIS长度,即最后答案 
      
    for (int i = 1;i <= n;i++){//遍历a数组 
        int zb = lower_bound(dp,dp + len + 1,a[i]) - dp;
        //找到第一个大于它的数(二分) 
        if(zb > len){//如果其长度大于答案长度 
            len++;//更新 
        }
        dp[zb] = a[i];//将dp数组末尾最小的数改为a[i] 
    }
      
    printf("%d",len);//输出 
    return 0;
} 

 

 

 

 

posted @ 2022-02-26 22:33  XDFZ武斌  阅读(135)  评论(0)    收藏  举报