标签:复杂 str http 需要 变化 二分查找 sequence 意思 最长单调子序列
(LIS Longest Increasing Subsequence)给定一个数列,从中删掉任意若干项剩余的序列叫做它的一个子序列,求它的最长的子序列,满足子序列中的元素是单调递增的。
例如给定序列{1,6,3,5,4},答案是3,因为{1,3,4}和{1,3,5}就是长度最长的两个单增子序列。
处看此题,怎么做? 万能的枚举?枚举全部2^n个子序列,找出最长的,固然可以,就是复杂度太高。我们为什么要枚举呢?因为要知道取了哪些数,其实我们只需要考虑上一个数和取了几个数就可以了吧?因为单增的意思是比前一个数大,我们要加入这个数的时候,只考虑它比之前加入的最后一个数大就可以了。而最长的意思是数的个数最多,我们只要知道数的总个数就可以了,没必要知道具体有哪些数。
让我们尝试一下用动态规划的思考办法。首先设置数列是a1, a2, a3…an,为了方便我们加入一项a0=-∞,后面我们将发现这会给我们带来极大的方便。int f[i]表示以第i个数结尾的最长单调子序列的长度, 那么我们看一下加入ai之前的最后一个数是aj,显然j < i并且aj < ai,我们有f(i) = f(j) + 1,因为往后面延长了一项嘛。那根据这个式子,我们显然应该选择最大的f(j),才能让f(i)最大。
于是我们有了递推关系f(i) = max{f(j)| j < i并且aj < ai} + 1,光有了递推关系还不够,初值呢? f(0) = 0,并且我们加入了a0=-∞,这样对每个i > 0,j总是存在的,大不了就达到下标0了嘛。
f[0] = 0; for i = 1 to n do f[i] = 0; for j = 0 to i – 1 do f[i] = max(f[i], f[j] + 1) endfor endfor
#include<cstdio> #include<cstring> using namespace std; int n,a[1000001],f[1000001],maxn; int main() { memset(f,-127,sizeof(f)); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { if(a[i]>f[maxn]) f[++maxn]=a[i]; else if(a[i]<f[maxn]) { int l=1,r=maxn; while(l<=r) { int m=(l+r)/2; if(a[i]<f[m]) r=m-1; else if(a[i]==f[m]) break; else l=m+1; } if(f[l]>a[i]) f[l]=a[i]; } } printf("%d",maxn); }
如果对你有所帮助,别忘了加好评哦;么么哒!!下次见!88
标签:复杂 str http 需要 变化 二分查找 sequence 意思 最长单调子序列
原文地址:http://www.cnblogs.com/cangT-Tlan/p/6219006.html