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)
第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; }
本文来自博客园,作者:XDFZ武斌,转载请注明原文链接:https://www.cnblogs.com/XDFZwb1523/p/15940769.html

浙公网安备 33010602011771号