zoukankan      html  css  js  c++  java
  • 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 }
    
    
  • 相关阅读:
    J2SE-反射
    c3p0 连接数据库失败的问题
    c# 调用存储过程
    存储过程使用truncate时
    Parcelable intent传递对象时,需要将该对象实现Parcelable 或者Serializable
    android intent 在打开设置activity的时候在监听事件的内部 适用setclass()方法时 不是直接适用this 关键字
    c# 读取appconfig文件
    Oracle 连接数据库的几种方式
    通过反射获得方法,和绑定事件
    js 验证
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/9282657.html
Copyright © 2011-2022 走看看