首页 > 代码库 > 51nod 1134 最长递增子序列

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;
}

  

  

51nod 1134 最长递增子序列