NYOJ 214.单调递增子序列(二)(动态规划)

来源:互联网 发布:最悲惨的人生 知乎 编辑:程序博客网 时间:2024/05/23 15:44
/*
描述
给定一整型数列{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

*/

思路:这道题是求一个数列中,最长的单调子序列。

首先,可以定义两个数组a[100010](储存原数列),dp[100010](储存最长子序列)。

然后,dp数组中的元素与a数组中的某个元素进行比较,如果这个元素比dp数组最后一个元素大,将这个元素储存到dp数组中。(这一部分可以用二分查找,找到比该元素大于或等于的元素的位置)

最后,输出dp数组的个数。

下面是代码实现:

#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;//memset(dp,0,sizeof(dp));//int i,j; for(i=0;i<n;i++)    scanf("%d",&a[i]); for(i=0;i<n;i++)//二分查找,找到大于或等于该元素的第一个位置 {int low=0,high=count,mid;    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)//若该位置是原dp数组的最后一位,count加1     count++;//for(j=count;j>=0;j--)//从dp数组的最后一位开始进行比较 //{                    // (这种方法用于数据量少的,用于数据量大的将有可能超时,需要用到二分查找)//if(a[i]>dp[j])   //若成立,储存到dp数组中 //{//    dp[j+1]=a[i];//    if(j==count)//    count++;//break;    //}//}        }printf("%d\n",count);}return 0;}

另外,还可以用lower_bound()函数进行查找(其实上面程序中的二分查找就相当于该函数)

下面是代码实现:

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;int main(){int n;int a[100005],dp[100005];while(~scanf("%d",&n)){fill(dp,dp+n,0x3f3f3f3f);for(int i=0;i<n;i++)scanf("%d",&a[i]);for(int i=0;i<n;i++)*(lower_bound(dp,dp+n,a[i]))=a[i];printf("%d\n",lower_bound(dp,dp+n,0x3f3f3f3f)-dp);}return 0;}


0 0
原创粉丝点击