51nod1134——(最长上升子序列)

给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
 
Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
Output
输出最长递增子序列的长度。
Input示例
8
5
1
6
8
2
4
5
10
Output示例
5


题意:最经典的最长上升子序列问题,给出了你一个包含n个数的最长上升子序列,要你求出在这个序列中,单调递增的子序列最长为多少?例如:1 9 4 3 5 2 6 7的最长上升子序列为1 3 5 6 7或1 4 5 6 7。
思路:最长上升子序列有几种解法(菜鸟的我只会两种),一种最简单的dp解法是O(n^2),这里用不上。我这里用的是nlogn的。可以声明一个数组dp【1.....n】,dp【i】的意义是什么?它记录的是在整个序列中,长度为 i 的上升子序列末尾元素的最小值。所有如果你当前输入的元素num大于dp【i】,那么你就可以确定当前长度为i+1的上升子序列的末尾元素为num,否则你就要找出dp【1....i】中第一个大于等于num的元素的位置 j,用num来替换dp【j】,这意味着长度为 j 的上升子序列的末尾元素被减小为num了。
而求第一个大于等于num的数的方法可以用二分,因为你在更新dp数组的时候,前面的那些数就是有序的了。当然更简单的可以用《algorithm》中的lower_bound函数,它返回的是有序数组中第一个大于或等于某个数的元素的地址。当所有的元素被输入完后,dp数组下标就是最长上升子序列元素的个数。当然这种方法只能求最长上升子序列元素的个数,无法求出每一个元素是什么。
这一篇博客详细模拟了上面这种方法的每一步,可以看着理解一下:https://blog.csdn.net/fire_to_cheat_/article/details/78297534

代码:
 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<string>
 6 #include<cmath>
 7 #include<algorithm>
 8 #include<stack> 
 9 #include<queue>
10 #define ll long long
11 #define inf 0x3f3f3f3f
12 #define pi 3.141592653589793238462643383279
13 using namespace std;
14 int main()
15 {
16     int n,num,dp[50005];
17     while(cin>>n)
18     {
19         scanf("%d",&num);
20         dp[0] = num;
21         int cnt = 1;
22         for(int i=1; i<n; ++i)
23         {
24             scanf("%d",&num);
25             if(dp[cnt-1] < num) dp[cnt++] = num;
26             else //lower_bound函数求第一个大于等于num的数 
27             {
28                 int p = lower_bound(dp,dp + cnt - 1,num) - dp; //数的地址减去基地址等于数组下标 
29                 dp[p] = num;
30             }
31             /*else // 二分法求第一个大于等于num的数 
32             {
33                 int low = 0,high = cnt-1;
34                 while(low <= high)
35                 {
36                     int mid = (low + high)/2;
37                     if(dp[mid] < num)
38                         low = mid + 1;
39                     else if(dp[mid] > num)
40                         high = mid - 1;
41                     else
42                     {
43                         low = mid;
44                         break;
45                     }
46                 }
47                 dp[low] = num;
48             }*/ 
49         }
50         cout<<cnt<<endl;
51     }
52 }
 
 

猜你喜欢

转载自www.cnblogs.com/tuyang1129/p/9282657.html
今日推荐