zoukankan      html  css  js  c++  java
  • nyist oj 214 单调递增子序列(二) (动态规划经典)

    单调递增子序列(二)

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:4
    描写叙述

    给定一整型数列{a1,a2...,an}(0<n<=100000)。找出单调递增最长子序列,并求出其长度。

    如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。

    输入
    有多组測试数据(<=7)
    每组測试数据的第一行是一个整数n表示序列中共同拥有n个整数,随后的下一行里有n个整数,表示数列中的全部元素.每一个整形数中间用空格间隔开(0<n<=100000)。
    数据以EOF结束 。
    输入数据保证合法(全为int型整数)!
    输出
    对于每组測试数据输出整形数列的最长递增子序列的长度,每一个输出占一行。
    例子输入
    7
    1 9 10 5 11 2 13
    2
    2 -1
    例子输出
    5
    1
    来源

    [521521]改编

    这个题和前面做的那个单调递增子序列题目意思是一样的,可是这个题目数据量比較大,用前面的那种方法就会超时。前面的那一种方法dp[i]:用来储存以ai为末尾的最长递增子序列的长度。时间复杂度是o(n2),这个题目的数据范围到了100000,用这样的方法就会超时;

    所以我们採用还有一种方法,用dp[i]:储存长度为i+1的递增序列中末尾元素的最小值;

    建立一个一维数组dp[ ],用dp[i]保存长度为i的单调子序列的末尾元素的值,用top保存单调子序列的最大长度。

    初始top=1,dp[1]=a1。

    然后。我们从前向后遍历序列An(i : 2~n)。显然,我们会遇到两种情况:

    1.a[i] > dp[top]。此时,我们把a[i]增加到长度为top的单调序列中,这时序列长度为top+1。top值也跟着更新,即dp[++top] = a[i]。

    2.a[i]<=dp[top]。此时,a[i]不能增加长度为top的单调序列。那它应该增加长度为多少的序列呢?

    做法是。从后向前遍历dp[ ] (j: top-1~1),直到满足条件 a[i] > dp[j],此时。类似于步骤1,我们能够把a[i]增加到长度为j的单调序列中。这时此序列长度为j+1;(这段话转载于http://www.cnblogs.com/mycapple/archive/2012/08/22/2651453.html

    假设直接这样做的话。时间复杂度也会达到o(n2),可是这里还能够优化。我们在遍历更新的时候能够採用更高效率的方法。这里我们能够採用二分搜索,对前面的a[i]进行更新。这样的方法的时间复杂度就是o(nlogn)

    以下是代码:

    #include <cstdio>
    #include <cstring>
    const int maxn=100001;
    int dp[maxn],a[maxn];
    int Binary_search(int len,int k)//二分搜索
    {//查找比第一个比dp[i]小或者是相等的位置
        int start,end,mid;
        start=1;
        end=len;
        while(start<=end)
        {
            mid=(start+end)>>1;
            if(k==dp[mid])
                return mid;
            if(k>dp[mid])
                start=mid+1;
            else
                end=mid-1;
        }
        return start;
    }
    int main()
    {
        int n,i,t,len;
        while(scanf("%d",&n)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            for(i=0;i<n;i++)
                scanf("%d",&a[i]);
             len=1;
             dp[1]=a[0];//这里要从1開始
             for(i=1;i<n;i++)
             {
                 t=Binary_search(len,a[i]);//通过二分搜索查找a[i]要插入的位置
                 dp[t]=a[i];//更新dp的值
                 if(t>len)//假设插入的位置在最后。更新最大的长度
                    len=t;
             }
             printf("%d
    ",len);
        }
    }
    

    以下是最优代码,好简短的:用了一个STL里面的lower_bound函数,这个函数就是二分查找。返回第一个比val小的位置,把这个函数使用熟练也会比較方便,与此相对的另一个upper_bound函数;http://blog.csdn.net/niushuai666/article/details/6734403  这个内容能够參考这篇博客

     
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAX=100100;
    int num[MAX],top=0;
    int main()
    {
    	int n;
    	while(~scanf("%d",&n))
    	{
    		scanf("%d",&num[0]);
    		top=1;
    		for(int i=1;i!=n;i++)
    		{
    			scanf("%d",&num[i]);
    			int * p=lower_bound(num,num+top,num[i]);
    			if(p-num==top) ++top;
    			*p=num[i];
    		}
    		printf("%d
    ",top);
    	}
    	
    }        




  • 相关阅读:
    c标签页面进行解析json
    Android 简述touch事件中的MotionEvent
    R中读取文件,找不到路径问题 No such file or directory
    文章标题
    Codeforces Beta Round #2 C. Commentator problem
    openfire 开发遇到的些问题
    BZOJ 刷题记录 PART 5
    公司又裁人了……
    最简单的基于FFmpeg的移动端样例:Android 视频转码器
    单片机: 简易计算器的实现(键盘)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5377228.html
Copyright © 2011-2022 走看看