首页 > 代码库 > POJ 2533 Longest Ordered Subsequence 最长上升子序列
POJ 2533 Longest Ordered Subsequence 最长上升子序列
最长上升子序列:
有两种基本方法:两个时间复杂度分别为O(n^2)和O(nlogn)。
O(n^2)
容易的出动态规划的递推公式dp[i]=max(dp[j])+1 j=1,2...i-1,dp[i]是以元素i结尾的最长子序列个数。
在O(n^2)的最长上升子序列中可以通过记录每个元素前缀元素位置的方式来得到整个的最长上升子序列。
代码:
int LISOn2(int a[],int tot) { for(int i=1; i<=tot; i++) { dp[i]=1; head[i]=-1; } for(int i=1; i<=tot; i++) { int m=0,h=-1; for(int j=1; j<i; j++) { if(a[i]>a[j]&&dp[j]>m) { m=dp[j]; h=j; } dp[i]=m+1; head[i]=h; } } int ans=0,pos=0; for(int i=1; i<=tot; i++) { if(dp[i]>ans) { ans=dp[i]; pos=i; } } int top=0; for(int i=pos; i!=-1; i=head[i]) { lis[top++]=a[i]; //cout<<lis[top-1]<<" "; } return ans; }
O(nlogn)
又称为又称作CMI算法。
其操作如下:
开辟一个栈b,每次取栈顶元素s和读到的元素a做比较,如果a>s,则置为栈顶;如果a<s,则二分查找栈中的比a大的第1个数,并替换。最终栈的大小即为最长递增子序列为长度
考察b栈内每个元素的含义,b[i] 表示所有长度为i的上升子序列中最小的最后一个数.
·举例:原序列为3,4,5,2,4,2
栈为3,4,5,此时读到2,则用2替换3,得到栈中元素为2,4,5,再读4,用4替换5,得到2,4,4,再读2,得到最终栈为2,2,4,最终得到的解是:
长度为1的上升子序列中最小的最后一个数是2 (2)
长度为2的上升子序列中最小的最后一个数是2 (2,2)长度为3的上升子序列中最小的最后一个数是4 (3,4,4)
可知没有长度为4的上升子序列,最长递增子序列长度为3. (3,4,4)
CMI本质是LIS问题的另一种动态规划思路。
CMI只能求LIS的长度和最后一个数,不能求LIS的序列!
所以求LIS的序列只能用O(n^2)算法。
代码:
int LISOnlogn(int a[],int tot) { int len=1; dp[1]=a[1]; for(int i=2; i<=tot; i++) { if(a[i]>dp[len]) dp[++len]=a[i]; else { int r=len,l=1; while(r>=l) { int mid=(r+l)/2; if(a[i]>=dp[mid]) l=mid+1; else r=mid-1; } dp[l]=a[i]; } } return len; }
参考资料:百度百科:LIS
题目链接:http://poj.org/problem?id=2533
本题是一道裸题,完整代码:
#include <iostream> #include <cstdio> #define maxn 1005 using namespace std; int a[maxn],dp[maxn],head[maxn],lis[maxn]; int LISOnlogn(int a[],int tot) { int len=1; dp[1]=a[1]; for(int i=2; i<=tot; i++) { if(a[i]>dp[len]) dp[++len]=a[i]; else { int r=len,l=1; while(r>=l) { int mid=(r+l)/2; if(a[i]>=dp[mid]) l=mid+1; else r=mid-1; } dp[l]=a[i]; } } return len; } int LISOn2(int a[],int tot) { for(int i=1; i<=tot; i++) { dp[i]=1; head[i]=-1; } for(int i=1; i<=tot; i++) { int m=0,h=-1; for(int j=1; j<i; j++) { if(a[i]>a[j]&&dp[j]>m) { m=dp[j]; h=j; } dp[i]=m+1; head[i]=h; } } int ans=0,pos=0; for(int i=1; i<=tot; i++) { if(dp[i]>ans) { ans=dp[i]; pos=i; } } int top=0; for(int i=pos; i!=-1; i=head[i]) { lis[top++]=a[i]; } return ans; } int main() { int tot; scanf("%d",&tot); for(int i=1; i<=tot; i++) scanf("%d",&a[i]); int ans=LISOn2(a,tot); //ans=LISOnlogn(a,tot); cout<<ans<<endl; return 0; }
POJ 2533 Longest Ordered Subsequence 最长上升子序列
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。