使用二分查找求解最长上升子序列

来源:互联网 发布:协同过滤算法 spark 编辑:程序博客网 时间:2024/06/06 04:34

题目链接:HLOJ 9948 气球排序(3秒版),由于时间延长到3秒,一般的LOS也能过,但使用本方法时间大大节省(2500ms vs. 187ms)。

#include<iostream>#include<vector>#include<cstdio> //ZOJ 用scanf,printf时必须包含此头文件using namespace std;const int N=20000;int v[N];//存放输入的数值int a[N];//辅助数组,存放左边小于中间数的数,右边大于中间数的数int f[N];//辅助数组,存放LOS长度//状态:f[i],以第i个元素(v[i])为最后一个元素的最长上升子序列的长度//方程:f[i]=max(f[j]+1, f[i]), 0<=j<i && v[i]>v[j]//初值:f[i]=1,0<=i<n,考虑只有v[i]一个数时的上升序列的长度//结果:f[]中的最大值int BSearch(vector <int> a, int t) //二分查找{int n=a.size(), low=0, high=n-1;while (low<=high){int mid=(low + high)/2;if (t==a[mid]) return mid;else if (t>a[mid]) low=mid+1;else high=mid-1;}return low;}int LosBS(int a[], int n) //使用二分查找的最长上升子序列{vector <int> tv; //存放构成最长上升子序列的数据tv.push_back(a[0]);for (int i=1; i<n; i++){int k=tv.size()-1;if (a[i]>tv[k]) //当前考虑的数(a[i])大于当前最长上升子序列(tv)的最后一个数则直接放到最后{tv.push_back(a[i]);}else //在当前最长上升子序列中使用二分查找求得存放当前考虑的数的位置并放入该数{int j=BSearch(tv, a[i]);tv[j]=a[i];}}return tv.size();}void run(){    int i, n, k=0;    scanf("%d", &n); fill(f, f+n, 0);for(i=0;i<n;i++) scanf("%d", &v[i]);int m=(n-1)/2;for (i=0;i<m;i++) {if (v[i]<v[m])a[k++]=v[i];}a[k++]=v[m];int l1=LosBS(a,k);k=0;for (i=m+1;i<n;i++) {if (v[i]>v[m])a[k++]=v[i];}int l2=LosBS(a,k);if (k==0) l2=0;     printf("%d\n", n-l1-l2);}int main(){#ifndef ONLINE_JUDGE    freopen("e:\\1.txt", "r", stdin);#endifint T;scanf("%d", &T);for(int i=1; i<=T; i++) run();return 0;}


0 0
原创粉丝点击