http://acm.pku.edu.cn/JudgeOnline/problem?id=2533
最长上升子序列:
有两种基本方法:两个时间复杂度分别为O(n^2)和O(nlogn)
先来看第1种:
动态规划:
对于给定数列E,元素个数为n,最长上升子序列Q满足对任意1<=i<j<=n,有Q[i]<Q[j],且E[i]<E[j]。
容易得出O(n^2)的DP递推公式:
D[i]=max{D[j]}+1;(1<=j<i且E[j]<E[i])
D[i]为以元素i结尾的最长子序列个数。
这样经过两重循环一次遍历可以得到最长上升子序列。
代码如下:
#include<iostream>
using namespace std;
int n;
int a[1001],b[1001];
int main()
{ int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=1;
}
for(i=1;i<=n;i++)
{ int maxx=0;
for(j=1;j<=i;j++)
{
if(a[i]>a[j]&&b[j]>maxx)
{ maxx=b[j];
}
}
b[i]=maxx+1;
}
int best=0;
for(i=1;i<=n;i++)
{ if(best<b[i])
best=b[i];
}
printf("%d\n",best);
system("pause");
return 0;
}
第2种方法时间复杂度为O(nlogn),用到了二分查找和贪心。
其操作如下:
开辟一个栈,每次取栈顶元素s和读到的元素a做比较,如果a>s,则加入栈;如果a<s,则二分查找栈中的比a大的第1个数,并替换。最后序列长度为栈的长度。
这也是很好理解的,对x和y,如果x<y且E[y]<E[x],用E[x]替换E[y],此时的最长序列长度没有改变但序列Q的''潜力''增大。
举例:原序列为1,5,8,3,6,7
栈为1,5,8,此时读到3,则用3替换5,得到栈中元素为1,3,8,再读6,用6替换8,得到1,3,6,再读7,得到最终栈为1,3,6,7,最长递增子序列为长度4。
代码如下:
#include<iostream>
using namespace std;
int n;
int a[1001],b[1001];
int rear;
int solve(int t)
{ int l=1,r=rear;
while(l<=r)
{ int mid=(l+r)>>1;
if(b[mid]>=t)//若为非递减序列,则为b[mid]>t
r=mid-1;
else
l=mid+1;
}
if(l>rear)
rear=l;
return l;
}
int main()
{ int i,j;
scanf("%d",&n);
rear=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[solve(a[i])]=a[i];
}
printf("%d\n",rear);
system("pause");
return 0;
}