51nod 1134 最长单增子序列

来源:互联网 发布:机械手g402鼠标宏编程 编辑:程序博客网 时间:2024/06/08 02:00

1 最基本的思路 dpi存储以i为末元素的最长的子序列的长度
2 优化思路 dpi存储长为i的子序列的最小末尾元素下标

我只说思路2
这种思路里,对于一个新元素
可能1:它比当前最长的子序列末尾要大,那么就把它接在后面
可能2:它没有当前最长子序列末尾大,那么就用查找(二分)查找一个属于它的区间,即“我该把它插到哪里”,这里我使用lower_bound查找,找到之后替换(用较小的数替换dp x中的值,)
关于lower_boudn参考

lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value 的值[1] 。该函数为C++ STL内的函数。

//@auther zhou//@Number 201408070203//@start time://@finish time:/*@此处注意:*//* 测试数据*/#include<iostream>#include<cstring>#include<vector>#include<cmath>#include<algorithm>#define  INF 1e9using namespace std;long long a[50005]={0};long long dp[50005]={0};int n;void dpcal1(){//策略1,o(n^2)每一个数循环查找其之前的所有dp,确定以它结尾的最长子序列的长度     for(int i=0;i<=n;i++){        for(int j=0;j<i;j++){            if(a[i]>a[j]){                dp[i]=max(dp[i],dp[j]+1);            }        }    }    long long ans=0;    for(int i=0;i<=n;i++){        ans=max(ans,dp[i]);    }    cout<<ans;}void dpcall2(){//优化策略,dpn计算长度为n的,且末尾元素最小的那一个,对于每一个新来的数,二分查找dp中末尾比它小的 最大的哪一项(可以证明dp是递增的)     int maxn=1;//保存当前最长的长度,其实也就是dpn扩展的下标     int temppos=0;    dp[1]=a[1];    for(int i=2;i<=n;i++){        if(a[i]>dp[maxn]){//比当前最长长度的末元素要大,就+1长度            dp[++maxn]=a[i];         }        else{            temppos=lower_bound(dp+1,dp+maxn+1,a[i])-dp;            dp[temppos]=a[i];        }    }    cout<<maxn;}int main(){    cin>>n;//  case1: on^2//  a[0]=-INF;//  for(int i=1;i<n;i++){//      cin>>a[i];//  }//  dpcal1();//  case2:    for(int i=1;i<=n;i++){        cin>>a[i];        dp[i]=1;    }    dpcall2();return 0;}
0 0
原创粉丝点击