NYOJ-214 单调递增子序列(二)

来源:互联网 发布:linux拷贝文件并改名 编辑:程序博客网 时间:2024/05/06 23:45

单调递增子序列(二)

时间限制: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型整数)!
输出
对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。
样例输入
71 9 10 5 11 2 1322 -1
样例输出
51
**思路来自挑战程序设计p65页下
简单的说就是最长上升子序列的长度是由它末尾数字的大小来决定的与前面的数字没有什么必然的关系,如果你能理解这句话,你就能明白在这里
这个dp数组的用途了。。。
*lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value 的值。
#include <iostream>#include <algorithm>using namespace std;const int INF = 0x6ffffff;//把dp数组初始化为一个极大的值 int dp[100010];int arr[100010];int main(){int n;while(cin>>n){int i;fill(dp,dp+n,INF);for(i=0;i<n;i++)cin>>arr[i];for(i=0;i<n;i++){int *p = lower_bound(dp,dp+n,arr[i]);//每次在dp数组中找到>=arr[i]的第一个元素,然后把它覆盖, *p = arr[i];} cout<<lower_bound(dp,dp+n,INF) - dp<<endl;//输出辅助数组的长度,就是最优解 }return 0;}


下面还有C语言版本的二分查找的解决方法,道理一样
#include<stdio.h>#include<string.h>int main(){int n;int a[100005],dp[100005],count;while(~scanf("%d",&n)){count=0;memset(dp,0x3f,sizeof(dp));int i;for(i=0;i<n;i++)    scanf("%d",&a[i]); for(i=0;i<n;i++){int low=0,high=count,mid;//二分查找>=a[i]的第一个值     while(low<=high)    {    mid=(low+high)/2;    if(dp[mid]>=a[i])    high=mid-1;    else    low=mid+1;    }dp[low]=a[i];//覆盖当前值 if(low==count){count++;//刷新边界 }        }printf("%d\n",count);}return 0;}


奈何我冒泡的算法如何打动你超时的心!!
0 0
原创粉丝点击