51nod 1134 最长递增子序列
给出长度为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
//第一种做法,放入一个数然后更新
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
long long a[100000],b[100000];
int main(){
int n;
while(cin>>n){
memset(a,1000000009,sizeof(a));
memset(b,1000000009,sizeof(b));
int i,j;
for(i=0;i<n;i++)
cin>>a[i];
int x=0;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(a[i]<b[j]){ //每次放入一个数,找到适当的位置更新
b[j]=a[i];
if(j>x) x=j;
break; //因为一个数只用一次更新,所以循环结束
}
}
}
cout<<x+1<<endl;
}
return 0;
}
//第二种runtime ……额 ……┭┮﹏┭┮……等我不这么菜了,再改
建立一个辅助数组c[n],c[i]储存的是子序列长度为i的序列最后一值即
子序列长度为i有多个,但是要求最后一个值最小,
比如 1, 4,7,3,8,2,1
1,4
1,3
1,2
1,1
从前往后遍历数组a[n],处理a[i-1]时,观察c数组,每个a数组中的值和
c数组中的值进行比较,找到合适的位置插入(若插入到c数组的末尾,那么
所求最长上升子序列长度+1,恩,,你应该隐约感受到了什么了吧,不错呢c数组的
长度就是最后我们所要求滴,撤回来),否则就替换掉c数组原来位置上的值
这有助于我们通过a数组计算b数组(b[i]中保存的是以a[i]为最后一个元素的
最长单调递增子序列) 若a[i]<a[j],就b[j]赋值b[i] c中药保存a[i]
由于c数组下标代表子序列长度,c数组中的值也是按递增序列排序,所以很符合二分
#include <iostream>
using namespace std;
int find(int *a,int len,int n){ //二分find
int l=0,r=len,mid=(l+r)>>1;
while(l<=r){
if(n>a[mid]) l=mid+1;
else if(n<a[mid]) r=mid-1;
else return mid;
mid=(l+r)>>1;
}
}
void init(int *a,int n){
for(int i=0;i<=n;i++)
a[i]=1000;
}
int main(){
int maxn,i,j,n,a[100],b[100],c[100];
while(cin>>n){
init(c,n+1);
for(i=0;i<n;i++)
cin>>a[i];
c[0]=-1; //天然最小值
c[1]=a[0]; //initialization
b[0]=1; //b[i]表示以a[i]结尾的最长单调递增子序列
for(i=1;i<n;i++){ //复杂度是N
j=find(c,n+1,a[i]); //复杂度logN的
c[j]=a[i];
b[i]=j;
}
for(maxn=i=0;i<n;i++) //遍历一遍找到最大值
if(b[i]>maxn)
maxn=b[i];
cout<<maxn<<endl;
}
return 0;
}
浙公网安备 33010602011771号